File: CacheEntryExtensions.cs
Web Access
Project: src\src\libraries\Microsoft.Extensions.Caching.Abstractions\src\Microsoft.Extensions.Caching.Abstractions.csproj (Microsoft.Extensions.Caching.Abstractions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Primitives;
 
namespace Microsoft.Extensions.Caching.Memory
{
    /// <summary>
    /// Provides extensions methods for <see cref="ICacheEntry"/> operations.
    /// </summary>
    public static class CacheEntryExtensions
    {
        /// <summary>
        /// Sets the priority for keeping the cache entry in the cache during a memory pressure tokened cleanup.
        /// </summary>
        /// <param name="entry">The entry to set the priority for.</param>
        /// <param name="priority">The <see cref="CacheItemPriority"/> to set on the entry.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry SetPriority(
            this ICacheEntry entry,
            CacheItemPriority priority)
        {
            entry.Priority = priority;
            return entry;
        }
 
        /// <summary>
        /// Expires the cache entry if the given <see cref="IChangeToken"/> expires.
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="expirationToken">The <see cref="IChangeToken"/> that causes the cache entry to expire.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry AddExpirationToken(
            this ICacheEntry entry,
            IChangeToken expirationToken)
        {
            ThrowHelper.ThrowIfNull(expirationToken);
 
            entry.ExpirationTokens.Add(expirationToken);
            return entry;
        }
 
        /// <summary>
        /// Sets an absolute expiration time, relative to now.
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="relative">The <see cref="TimeSpan"/> representing the expiration time relative to now.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry SetAbsoluteExpiration(
            this ICacheEntry entry,
            TimeSpan relative)
        {
            entry.AbsoluteExpirationRelativeToNow = relative;
            return entry;
        }
 
        /// <summary>
        /// Sets an absolute expiration date for the cache entry.
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="absolute">A <see cref="DateTimeOffset"/> representing the expiration time in absolute terms.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry SetAbsoluteExpiration(
            this ICacheEntry entry,
            DateTimeOffset absolute)
        {
            entry.AbsoluteExpiration = absolute;
            return entry;
        }
 
        /// <summary>
        /// Sets how long the cache entry can be inactive (for example, not accessed) before it will be removed.
        /// This method does not extend the entry lifetime beyond the absolute expiration (if set).
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="offset">A <see cref="TimeSpan"/> representing a sliding expiration.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry SetSlidingExpiration(
            this ICacheEntry entry,
            TimeSpan offset)
        {
            entry.SlidingExpiration = offset;
            return entry;
        }
 
        /// <summary>
        /// Fires the given callback after the cache entry is evicted from the cache.
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="callback">The callback to run after the entry is evicted.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry RegisterPostEvictionCallback(
            this ICacheEntry entry,
            PostEvictionDelegate callback)
        {
            ThrowHelper.ThrowIfNull(callback);
 
            return entry.RegisterPostEvictionCallbackNoValidation(callback, state: null);
        }
 
        /// <summary>
        /// Fires the given callback after the cache entry is evicted from the cache.
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="callback">The callback to run after the entry is evicted.</param>
        /// <param name="state">The state to pass to the post-eviction callback.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry RegisterPostEvictionCallback(
            this ICacheEntry entry,
            PostEvictionDelegate callback,
            object? state)
        {
            ThrowHelper.ThrowIfNull(callback);
 
            return entry.RegisterPostEvictionCallbackNoValidation(callback, state);
        }
 
        private static ICacheEntry RegisterPostEvictionCallbackNoValidation(
            this ICacheEntry entry,
            PostEvictionDelegate callback,
            object? state)
        {
            entry.PostEvictionCallbacks.Add(new PostEvictionCallbackRegistration()
            {
                EvictionCallback = callback,
                State = state
            });
            return entry;
        }
 
        /// <summary>
        /// Sets the value of the cache entry.
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="value">The value to set on the <paramref name="entry"/>.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry SetValue(
            this ICacheEntry entry,
            object? value)
        {
            entry.Value = value;
            return entry;
        }
 
        /// <summary>
        /// Sets the size of the cache entry value.
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="size">The size to set on the <paramref name="entry"/>.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry SetSize(
            this ICacheEntry entry,
            long size)
        {
            if (size < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(size), size, $"{nameof(size)} must be non-negative.");
            }
 
            entry.Size = size;
            return entry;
        }
 
        /// <summary>
        /// Applies the values of an existing <see cref="MemoryCacheEntryOptions"/> to the entry.
        /// </summary>
        /// <param name="entry">The <see cref="ICacheEntry"/>.</param>
        /// <param name="options">Set the values of these options on the <paramref name="entry"/>.</param>
        /// <returns>The <see cref="ICacheEntry"/> for chaining.</returns>
        public static ICacheEntry SetOptions(this ICacheEntry entry, MemoryCacheEntryOptions options)
        {
            ThrowHelper.ThrowIfNull(options);
 
            entry.AbsoluteExpiration = options.AbsoluteExpiration;
            entry.AbsoluteExpirationRelativeToNow = options.AbsoluteExpirationRelativeToNow;
            entry.SlidingExpiration = options.SlidingExpiration;
            entry.Priority = options.Priority;
            entry.Size = options.Size;
 
            foreach (IChangeToken expirationToken in options.ExpirationTokens)
            {
                entry.AddExpirationToken(expirationToken);
            }
 
            for (int i = 0; i < options.PostEvictionCallbacks.Count; i++)
            {
                PostEvictionCallbackRegistration postEvictionCallback = options.PostEvictionCallbacks[i];
                if (postEvictionCallback.EvictionCallback is null)
                    ThrowNullCallback(i, nameof(options));
 
                entry.RegisterPostEvictionCallbackNoValidation(postEvictionCallback.EvictionCallback, postEvictionCallback.State);
            }
 
            return entry;
        }
 
        [DoesNotReturn]
        private static void ThrowNullCallback(int index, string paramName)
        {
            string message =
                $"MemoryCacheEntryOptions.PostEvictionCallbacks contains a PostEvictionCallbackRegistration with a null EvictionCallback at index {index}.";
            throw new ArgumentException(message, paramName);
        }
    }
}