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构造函数之前正在构造懒惰?
  • 是否有可能在不打破单例语义的情况下实现我想要的?

Encapsulate Lazy<T>

您正在寻找的抽象是记忆函数。在这种函数中,你修改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>来给出相同的行为。