正在缓存扩展方法的返回值
本文关键字:返回值 方法 扩展 缓存 | 更新日期: 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
{
}