C#应该有一个懒惰的关键字吗

C#应该有一个懒惰的关键字吗,c#,.net,lazy-initialization,C#,.net,Lazy Initialization,C#是否应该有一个lazy关键字来简化惰性初始化 例如 而不是 private string _backingField; public string LazyInitializeString { get { if (_backingField == null) _backingField = GetStringFromDatabase(); return _

C#是否应该有一个lazy关键字来简化惰性初始化

例如

而不是

    private string _backingField;

    public string LazyInitializeString
    {
        get
        {
            if (_backingField == null)
                _backingField = GetStringFromDatabase();
            return _backingField;
        }
    }

我不知道关键字,但它现在有一个类型

  • 它正式成为.Net Framework 4.0的一部分
  • 它允许延迟加载
    成员的值
  • 它支持
    lambda表达式
    方法
    来提供值
例子: 在上面的测试代码中,
GetStringFromDatabase()
只被调用一次。我想这正是你想要的

编辑: 在得到@dthorpe和@Joe的评论后,我只能说以下是最短的:

public class ClassWithLazyMember
{
    Lazy<String> lazySource;
    public String LazyValue { get { return lazySource.Value; } }

    public ClassWithLazyMember()
    {
        lazySource = new Lazy<String>(GetStringFromDatabase);
    }

    public String GetStringFromDatabase()
    {
        return "Hello, Lazy World!";
    }
}
带有LazMember的公共类
{
懒惰懒散的人;
公共字符串LazyValue{get{return lazySource.Value;}}
公共类WithLazymember()
{
lazySource=new Lazy(GetStringFromDatabase);
}
公共字符串GetStringFromDatabase()
{
返回“你好,懒惰的世界!”;
}
}
因为以下内容不可编译:

public Lazy<String> LazyInitializeString = new Lazy<String>(() =>
{
    return GetStringFromDatabase();
});
public Lazy Lazy initializestring=new Lazy(()=>
{
返回GetStringFromDatabase();
});
而该属性的类型是
Lazy
而不是
String
。您始终需要使用
lazyiinitializestring.value
访问它的值

而且,我愿意听取关于如何缩短它的建议。

您考虑过使用吗

public Lazy Lazy initializestring=new Lazy(()=>
{
返回GetStringFromDatabase();
});

(这确实有一个缺点,那就是你需要使用
LazyInitializeString.Value
,而不仅仅是
LazyInitializeString

好的,你在评论中说
Lazy
对你来说是不够的,因为它是只读的,你必须调用
.Value

不过,很明显,我们需要的是类似的东西——我们已经有了一种语法来描述要调用但不立即调用的动作(实际上我们有三种语法:lambda、委托创建和裸方法名,作为后者的快捷方式——我们最不需要的是第四种)

但是我们可以很快地把它组合起来

public enum SettableLazyThreadSafetyMode // a copy of LazyThreadSafetyMode - just use that if you only care for .NET4.0
{
    None,
    PublicationOnly,
    ExecutionAndPublication
}
public class SettableLazy<T>
{
    private T _value;
    private volatile bool _isCreated;
    private readonly Func<T> _factory;
    private readonly object _lock;
    private readonly SettableLazyThreadSafetyMode _mode;
    public SettableLazy(T value, Func<T> factory, SettableLazyThreadSafetyMode mode)
    {
        if(null == factory)
            throw new ArgumentNullException("factory");
        if(!Enum.IsDefined(typeof(SettableLazyThreadSafetyMode), mode))
           throw new ArgumentOutOfRangeException("mode");
        _lock = (_mode = mode) == SettableLazyThreadSafetyMode.None ? null : new object();
        _value = value;
        _factory = factory;
        _isCreated = true;
    }
    public SettableLazy(Func<T> factory, SettableLazyThreadSafetyMode mode)
        :this(default(T), factory, mode)
    {
        _isCreated = false;
    }
    public SettableLazy(T value, SettableLazyThreadSafetyMode mode)
        :this(value, () => Activator.CreateInstance<T>(), mode){}
    public T Value
    {
        get
        {
            if(!_isCreated)
                switch(_mode)
                {
                    case SettableLazyThreadSafetyMode.None:
                        _value = _factory.Invoke();
                        _isCreated = true;
                        break;
                    case SettableLazyThreadSafetyMode.PublicationOnly:
                        T value = _factory.Invoke();
                        if(!_isCreated)
                            lock(_lock)
                                if(!_isCreated)
                                {
                                    _value = value;
                                    Thread.MemoryBarrier(); // ensure all writes involved in setting _value are flushed.
                                    _isCreated = true;
                                }
                        break;
                    case SettableLazyThreadSafetyMode.ExecutionAndPublication:
                        lock(_lock)
                        {
                            if(!_isCreated)
                            {
                                _value = _factory.Invoke();
                                Thread.MemoryBarrier();
                                _isCreated = true;
                            }
                        }
                        break;
                }
            return _value;
        }
        set
        {
            if(_mode == SettableLazyThreadSafetyMode.None)
            {
                _value = value;
                _isCreated = true;
            }
            else
                lock(_lock)
                {
                    _value = value;
                    Thread.MemoryBarrier();
                    _isCreated = true;
                }
        }
    }
    public void Reset()
    {
        if(_mode == SettableLazyThreadSafetyMode.None)
        {
            _value = default(T); // not strictly needed, but has impact if T is, or contains, large reference type and we really want GC to collect.
            _isCreated = false;
        }
        else
            lock(_lock) //likewise, we could skip all this and just do _isCreated = false, but memory pressure could be high in some cases
            {
                _value = default(T);
                Thread.MemoryBarrier();
                _isCreated = false;
            }
    }
    public override string ToString()
    {
        return Value.ToString();
    }
    public static implicit operator T(SettableLazy<T> lazy)
    {
        return lazy.Value;
    }
    public static implicit operator SettableLazy<T>(T value)
    {
        return new SettableLazy<T>(value, SettableLazyThreadSafetyMode.ExecutionAndPublication);
    }
}
public enum SettableLazyThreadSafetyMode//LazyThreadSafetyMode的副本-如果您只关心.NET4.0,请使用它
{
没有一个
仅限出版物,
执行与出版
}
公共类SettableLazy
{
私人T_值;
创建私有易失性布尔;
私有只读功能工厂;
私有只读对象_锁;
私有只读SettableLazyThreadSafetyMode_模式;
公共SettableLazy(T值,函数工厂,SettableLazyThreadSafetyMode模式)
{
如果(空==工厂)
抛出新的异常(“工厂”);
如果(!Enum.IsDefined(typeof(SettableLazyThreadSafetyMode),mode))
抛出新ArgumentOutOfRangeException(“模式”);
_lock=(_mode=mode)==setTableLazyThreadSafetMode.None?null:new object();
_价值=价值;
_工厂=工厂;
_isCreated=true;
}
公共SettableLazy(函数工厂,SettableLazyThreadSafetyMode模式)
:此(默认(T)、工厂、模式)
{
_isCreated=false;
}
公共SettableLazy(T值,SettableLazyThreadSafetyMode模式)
:此(值,()=>Activator.CreateInstance(),模式){}
公共价值
{
得到
{
如果(!\u已创建)
开关(_模式)
{
案例设置LazyThreadSafetyMode。无:
_值=_factory.Invoke();
_isCreated=true;
打破
案例集LazyThreadSafetyMode.PublicationOnly:
T值=_factory.Invoke();
如果(!\u已创建)
锁
如果(!\u已创建)
{
_价值=价值;
Thread.MemoryBarrier();//确保刷新设置_值所涉及的所有写入操作。
_isCreated=true;
}
打破
案例集LazyThreadSafetyMode.ExecutionAndPublication:
锁
{
如果(!\u已创建)
{
_值=_factory.Invoke();
Thread.MemoryBarrier();
_isCreated=true;
}
}
打破
}
返回_值;
}
设置
{
if(_mode==SettableLazyThreadSafetyMode.None)
{
_价值=价值;
_isCreated=true;
}
其他的
锁
{
_价值=价值;
Thread.MemoryBarrier();
_isCreated=true;
}
}
}
公共无效重置()
{
if(_mode==SettableLazyThreadSafetyMode.None)
{
_value=default(T);//这不是严格需要的,但如果T是或包含大型引用类型,并且我们确实希望GC收集,则会产生影响。
_isCreated=false;
}
其他的
lock(_lock)//同样,我们可以跳过所有这些,只需执行_isCreated=false,但在某些情况下内存压力可能很高
{
_值=默认值(T);
Thread.MemoryBarrier();
_isCreated=false;
}
}
公共重写字符串ToString()
{
返回值.ToString();
}
公共静态隐式运算符T(SettableLazy)
{
返回lazy.Value;
}
公共静态隐式运算符SettableLazy(tV
public class ClassWithLazyMember
{
    Lazy<String> lazySource;
    public String LazyValue { get { return lazySource.Value; } }

    public ClassWithLazyMember()
    {
        lazySource = new Lazy<String>(GetStringFromDatabase);
    }

    public String GetStringFromDatabase()
    {
        return "Hello, Lazy World!";
    }
}
public Lazy<String> LazyInitializeString = new Lazy<String>(() =>
{
    return GetStringFromDatabase();
});
public Lazy<String> LazyInitializeString = new Lazy<String>(() =>
{
    return GetStringFromDatabase();
});
public enum SettableLazyThreadSafetyMode // a copy of LazyThreadSafetyMode - just use that if you only care for .NET4.0
{
    None,
    PublicationOnly,
    ExecutionAndPublication
}
public class SettableLazy<T>
{
    private T _value;
    private volatile bool _isCreated;
    private readonly Func<T> _factory;
    private readonly object _lock;
    private readonly SettableLazyThreadSafetyMode _mode;
    public SettableLazy(T value, Func<T> factory, SettableLazyThreadSafetyMode mode)
    {
        if(null == factory)
            throw new ArgumentNullException("factory");
        if(!Enum.IsDefined(typeof(SettableLazyThreadSafetyMode), mode))
           throw new ArgumentOutOfRangeException("mode");
        _lock = (_mode = mode) == SettableLazyThreadSafetyMode.None ? null : new object();
        _value = value;
        _factory = factory;
        _isCreated = true;
    }
    public SettableLazy(Func<T> factory, SettableLazyThreadSafetyMode mode)
        :this(default(T), factory, mode)
    {
        _isCreated = false;
    }
    public SettableLazy(T value, SettableLazyThreadSafetyMode mode)
        :this(value, () => Activator.CreateInstance<T>(), mode){}
    public T Value
    {
        get
        {
            if(!_isCreated)
                switch(_mode)
                {
                    case SettableLazyThreadSafetyMode.None:
                        _value = _factory.Invoke();
                        _isCreated = true;
                        break;
                    case SettableLazyThreadSafetyMode.PublicationOnly:
                        T value = _factory.Invoke();
                        if(!_isCreated)
                            lock(_lock)
                                if(!_isCreated)
                                {
                                    _value = value;
                                    Thread.MemoryBarrier(); // ensure all writes involved in setting _value are flushed.
                                    _isCreated = true;
                                }
                        break;
                    case SettableLazyThreadSafetyMode.ExecutionAndPublication:
                        lock(_lock)
                        {
                            if(!_isCreated)
                            {
                                _value = _factory.Invoke();
                                Thread.MemoryBarrier();
                                _isCreated = true;
                            }
                        }
                        break;
                }
            return _value;
        }
        set
        {
            if(_mode == SettableLazyThreadSafetyMode.None)
            {
                _value = value;
                _isCreated = true;
            }
            else
                lock(_lock)
                {
                    _value = value;
                    Thread.MemoryBarrier();
                    _isCreated = true;
                }
        }
    }
    public void Reset()
    {
        if(_mode == SettableLazyThreadSafetyMode.None)
        {
            _value = default(T); // not strictly needed, but has impact if T is, or contains, large reference type and we really want GC to collect.
            _isCreated = false;
        }
        else
            lock(_lock) //likewise, we could skip all this and just do _isCreated = false, but memory pressure could be high in some cases
            {
                _value = default(T);
                Thread.MemoryBarrier();
                _isCreated = false;
            }
    }
    public override string ToString()
    {
        return Value.ToString();
    }
    public static implicit operator T(SettableLazy<T> lazy)
    {
        return lazy.Value;
    }
    public static implicit operator SettableLazy<T>(T value)
    {
        return new SettableLazy<T>(value, SettableLazyThreadSafetyMode.ExecutionAndPublication);
    }
}
private SettableLazy<string> _backingLazy = new SettableLazy<string>(GetStringFromDatabase);

public string LazyInitializeString
{
    get
    {
        return _backingLazy;
    }
    set
    {
        _backingLazy = value;
    }
}