Encapsulate Lazy<T>
本文关键字:gt lt Lazy Encapsulate | 更新日期: 2023-09-27 18:03:39
在多次需要实现Lazy<T>
模式之后,我想到了将整个模式放入一个类中以隐藏Lazy实现的想法。
在"为我的服务加载一个单例配置对象"的例子中,我做了这样的事情:
public interface IConfigurationProvider<T>
{
T GetConfiguration();
}
public abstract class SingletonConfigurationProvider<TConfiguration> : IConfigurationProvider<TConfiguration>
{
private static readonly Lazy<TConfiguration> _lazy =
new Lazy<TConfiguration>(_loadConfiguration);
private static Func<TConfiguration> _loadConfiguration;
private SingletonConfigurationProvider() { }
public SingletonConfigurationProvider(Func<TConfiguration> LoadConfig)
{
_loadConfiguration = LoadConfig;
}
public TConfiguration GetConfiguration()
{
return _lazy.Value;
}
}
我的目标是从"外部"获得这样做的简单性:
public class ConfigTest : SingletonConfigurationProvider<ObjectTest>
{
public ConfigTest()
: base(Load)
{
}
public static ObjectTest Load()
{
return new ObjectTest()
{
testInt = 3,
testString = "Hi"
};
}
}
要点是:
- 它编译,但它在运行时中断,"TypeInitialization Exception"说
_loadConfiguration
不能为空。是不是因为在SingletonConfigurationProvider
构造函数之前正在构造懒惰? - 是否有可能在不打破单例语义的情况下实现我想要的?
您正在寻找的抽象是记忆函数。在这种函数中,你修改getter函数,使它实现一种"只执行一次"的模式。未经测试的代码,但大致;
public Func<T> Memoize(Func<T> slowFunction) {
bool evaluated = false;
T value = default(T);
return () => {
if (!evaluated) {
value = slowFunction();
evaluated = true;
}
return value;
};
}
现在你有一个函数可以这样使用;
Func<TConfiguration> onceOnlyLoad = Memoise(Load);
现在你可以调用onceOnlyLoad()
,只要你喜欢,它只会加载配置第一次调用它。
如果你愿意,你可以在内部使用Lazy<T>
来给出相同的行为。