需要帮助分析.NET缓存扩展方法

时间:2011-01-03 18:30:58

标签: .net caching

我有以下扩展名

Public Module CacheExtensions
    Sub New()
    End Sub

    Private sync As New Object()
    Public Const DefaultCacheExpiration As Integer = 1200 ''# 20 minutes

    <Extension()> 
    Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal generator As Func(Of T)) As T
        Return cache.GetOrStore(key, If(generator IsNot Nothing, generator(), Nothing), DefaultCacheExpiration)
    End Function

    <Extension()> 
    Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal generator As Func(Of T), ByVal expireInSeconds As Double) As T
        Return cache.GetOrStore(key, If(generator IsNot Nothing, generator(), Nothing), expireInSeconds)
    End Function

    <Extension()> 
    Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal obj As T) As T
        Return cache.GetOrStore(key, obj, DefaultCacheExpiration)
    End Function

    <Extension()> 
    Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal obj As T, ByVal expireInSeconds As Double) As T
        Dim result = cache(key)

        If result Is Nothing Then

            SyncLock sync
                If result Is Nothing Then
                    result = If(obj IsNot Nothing, obj, Nothing)
                    cache.Insert(key, result, Nothing, DateTime.Now.AddSeconds(expireInSeconds), cache.NoSlidingExpiration)
                End If
            End SyncLock
        End If

        Return DirectCast(result, T)

    End Function

End Module

从这里开始,我使用扩展名为TagService来获取标签列表

    Public Function GetTagNames() As List(Of String) Implements Domain.ITagService.GetTags
        ''# We're not using a dynamic Cache key because the list of TagNames
        ''# will persist across all users in all regions.
        Return HttpRuntime.Cache.GetOrStore(Of List(Of String))("TagNamesOnly",
                                                                Function() _TagRepository.Read().Select(Function(t) t.Name).OrderBy(Function(t) t).ToList())
    End Function

除非我在_TagRepository.Read()上设置断点,否则所有这些都非常简单。问题是,当我认为只有在Result Is Nothing

时调用它时,它才会被调用。

我在这里错过了什么吗?

编辑:对于你们伙计们,这里是C#等价物

public static class CacheExtensions
{

    private static object sync = new object();
    public const int DefaultCacheExpiration = 20;

    public static T GetOrStore<T>( this Cache cache, string key, Func<T> generator ) {
        return cache.GetOrStore( key, generator != null ? generator() : default( T ), DefaultCacheExpiration );
    }

    public static T GetOrStore<T>( this Cache cache, string key, Func<T> generator, double expireInMinutes ) {
        return cache.GetOrStore( key, generator != null ? generator() : default( T ), expireInMinutes );
    }

    public static T GetOrStore<T>( this Cache cache, string key, T obj ) {
        return cache.GetOrStore( key, obj, DefaultCacheExpiration );
    }

    public static T GetOrStore<T>( this Cache cache, string key, T obj, double expireInMinutes ) {
        var result = cache[key];

        if ( result == null ) {

            lock ( sync ) {
                if ( result == null ) {
                    result = obj != null ? obj : default( T );
                    cache.Insert( key, result, null, DateTime.Now.AddMinutes( expireInMinutes ), Cache.NoSlidingExpiration );
                }
            }
        }

        return (T)result;

    }

}

和电话

    return HttpRuntime.Cache.GetOrStore<List<string>>("TagNamesOnly", () => _TagRepository.Read().Select(t => t.Name).OrderBy(t => t).ToList());

2 个答案:

答案 0 :(得分:1)

GetOrStore的签名,以及它的实现,不包含你正在发送的Func的评估。我真的不知道目前发生了什么(或者它是否真的有效)。看来你正在为你的缓存添加一个Func。

public const int DefaultCacheExpiration = 20;
private static readonly Object SyncRoot = new Object();
public static T GetOrStore<T>(this Cache cache, String key, Func<T> itemGenerator, Double expireInSeconds = DefaultCacheExpiration) {
    var item = cache[key];
    if (item != null)
        return (T)item;

    lock (SyncRoot) {
        // Fetch a second time to check if anyone have
        // added it while we blocked waiting for the lock.
        item = cache[key];
        if (item != null)
            return (T)item;

        // Invoke the almighty itemGenerator to execute,
        // and generate, the item that should be inserted
        // into the cache.
        item = itemGenerator.Invoke();
        cache.Insert(key, item, null, DateTime.Now.AddSeconds(expireInSeconds), Cache.NoSlidingExpiration);
        return (T)item;
    }
}

public static T GetOrStore<T>(this Cache cache, String key, T newItem, Double expireInSeconds = DefaultCacheExpiration) {
    return cache.GetOrStore(key, () => newItem, expireInSeconds);
}

如果没有这样做,请查看您的asp.net缓存设置和服务器上的可用内存量。缓存在低内存条件下不起作用。

答案 1 :(得分:1)

问题是你正在调用一个调用你的方法的重载方法,而@Simon Svensson指出你调用的方法不是你发布的方法。这是您实际调用的方法的C#版本:

return cache.GetOrStore( key, generator != null ? generator() : default( T ), DefaultCacheExpiration )

如果第二个参数传递了非空值,你应该看到第二个参数调用generator()

<强>已更新

问题与缓存没有关系,它所调用的重载方法正在执行lambda方法。如果您真的打算按照概述调用方法,则必须将其更改为:

''# Fix StackOverflow Code Coloring Bug     
<Extension()>
Public Function GetOrStore(Of T)(ByVal cache As Cache, ByVal key As String, ByVal generator As Func(Of T)) As T
    ''# Null value to pass to first call. We can not use Nothing because VB can not infer the overload type
    Dim NV As Object = Nothing
    ''# Call the primary method passing a null value
    Dim Ret = cache.GetOrStore(key, NV, DefaultCacheExpiration)
    ''# If that call returns nothing call our generator() method and then re-call the main method
    If (Ret Is Nothing) AndAlso (generator IsNot Nothing) Then
        Ret = cache.GetOrStore(key, generator(), DefaultCacheExpiration)
    End If
    Return Ret
End Function

我没有对此进行过测试,但是它或者非常接近的东西应该可以得到你想要的东西。这也是为什么我不是lambdas的忠实粉丝。这个想法很棒,但是人们倾向于将这么多的东西混在一起并创建不可读的代码。我宁愿有10行我能阅读而不是1行同样的东西。