正在缓存扩展方法的返回值

本文关键字:返回值 方法 扩展 缓存 | 更新日期: 2023-09-27 18:21:28

以下是伪代码,如果我可以修改有问题的类,它会是什么样子

public class Foo
{
    private TheDataType _Data;
    public TheDataType GetData()
    {
        if (_Data != null)
            return _Data;
        // fetch/generate data
        return _Data;
    }
}

如何将其转化为扩展方法?_Data的定义/范围是困扰我的…

========================================

这可能是最接近我想要的,但对于如此简单的来说,感觉有些过头了

public static class FooExtensions
{
    private static ConcurrentDictionary<Foo,TheDataType> DataCache = new ConcurrentDictionary<Foo,TheDataType>();
    public static TheDataType GetData(this Foo foo)
    {
        TheDataType data;
        if (DataCache.TryGetValue(foo, out data))
            return data
        // fetch/generate data
        DataCache.Add(foo, data);
        return data;
    }
}

正在缓存扩展方法的返回值

您可以让您的扩展方法使用缓存管理器类(自定义或内置于框架中),该类根据实例的某些唯一标识符跟踪数据:

public static DataType GetData( this Foo obj )
{
    DataType retVal;
    // this sample doesn't show any locking, i.e. it is not thread safe
    // if cache manager contains data return from there
    if( CacheManager.HasData( obj.UniqueId ) )
    {
         retVal = CacheManager.GetData( obj.UniqueId );
    }    
    else
    {
         // otherwise invoke a method on obj and add to cache
         retVal = obj.GetData();
         CacheManager.Add( obj.UniqueId, retVal );
    }
    return retVal;
}

然而,我觉得这是对扩展方法的潜在滥用,尽管它在语法上很干净。这将取决于它的使用环境以及副作用的明显程度。例如,如果另一个开发人员不知道GetData()正在使用缓存、缓存过期不明确等,那么他们将很难进行故障排除。

这非常适合函数缓存,我在这篇博客文章中对此进行了描述。这个想法是将一个带有一个参数的函数转换为另一个函数,该函数缓存原始参数的结果:

public static Func<TKey, TValue> Cached<TKey, TValue>(this Func<TKey, TValue> valueFunction)
{
    var cache = new Dictionary<TKey, TValue>();
    return key =>
    {
        TValue value;
        if(!cache.TryGetValue(key, out value))
        {
            value = valueFunction(key);
            cache[key] = value;
        }
        return value;
    };
}

缓存字典嵌入到返回的闭包中,因此它将与我们返回的函数具有相同的生存期。

您可以使用它,将原来的调用替换为新函数:来获取数据

public class UsesTheDataType
{
    private readonly Func<Foo, TheDataType> _generateData;
    public UsesTheDataType()
    {
        _generateData = GenerateData;
        _generateData = _generateData.Cached();
    }
    public void UseTheDataType(Foo foo)
    {
        var theDataType = _generateData(foo);
        // theDataType is either a new value or cached value
    }
    private TheDataType GenerateData(Foo foo)
    {
        // Only called the first time for each foo
    }
}

这里很好的部分是,所有函数的缓存都只写一次,所以无论必须缓存什么,都可以重用相同的方法。这也避免了由于使用静态缓存而可能导致的内存泄漏。

这也可以以线程安全的方式进行。有关演练,请参见本系列的第二篇文章。

我不太确定你想要实现什么,但如果我遵循,它看起来会是这样的。

public static class FlargExtensions
{
    private static Flarg flarg;
    public static Flarg GetData(this Flarg flarg)
    {
        if (FlargExtensions.flarg != null)
            return Class1.flarg;
        FlargExtensions.flarg = new Flarg();
        return FlargExtensions.flarg;
    }
}
public class Flarg
{
}