繁体   English   中英

有什么理由不使用null-coalescing运算符进行延迟初始化?

[英]Any good reasons to not use null-coalescing operator for lazy initialization?

问候我今天做了一些懒惰的初始化代码,并想到为什么不使用null-coalescing运算符来做这个,它更短,但后来我认为这样做有任何开销或额外成本。

下面是简化的示例代码,显示了一个用于延迟初始化的更常见的表单,然后是一个使用null-coalescing运算符的表单。 它们具有完全相同的结果,并且看起来相同。 我的第一个想法是,在创建了对象之后,现在有一个额外的赋值给它自己使用?? 这是一个非问题,编译器/ JIT优化了一些如何,是否有更邪恶的事情,你永远不应该做懒惰的初始化?? ,或者它是完全安全的,没有坏的魔力可以来自它。

private MyLazyObject _lazyObject;

public MyLazyObject GetMyLazyObjectUsingMoreCommonMethod()
{
    if (_lazyObject != null)
        return _lazyObject;

    _lazyObject = new MyLazyObject();

    return _lazyObject;
}

public MyLazyObject GetMyLazyObjectUsingNullCoalescingOpMethod()
{
    _lazyObject = _lazyObject ?? new MyLazyObject();
    return _lazyObject;
}

是的,一个叫做线程安全的小东西。 你给出的两个方法在功能上是等价的,所以null合并运算符本身并不坏,但是你列出的方法都不是线程安全的,所以如果两个线程试图同时调用你的Get方法,你最终可能会产生两个MyLazyObject 这可能不是什么大问题,但它可能不是你所希望的。

如果您使用的是.NET 4,请使用Lazy

private Lazy<MyLazyObject> _lazyObject = 
    new Lazy<MyLazyObject>(() => new MyLazyObject());

public MyLazyObject MyLazyObject {get {return _lazyObject.Value;}}

代码简洁,易于理解,并且线程安全。

它非常安全且定义良好 - 事实上,它意味着编译器可以只复制堆栈的头部(dup)并存储一次,而不是存储字段,load-field。

它唯一出现问题的是c#1.2(.NET 1.1),它不存在。

句法糖中的空合并运算符。 本质上它与您的第一个示例相同,我不相信JIT编译器对它进行了特殊的优化。 你应该更关心的是你的方法的线程安全性。 null合并运算符不是原子的,这意味着您应该确保在返回之前以线程安全的方式实例化MyLazyObject

您甚至可以使用第一种方法的代码:

public MyLazyObject GetMyLazyObjectUsingMoreCommonMethod()
{
    if (_lazyObject == null)
        _lazyObject = new MyLazyObject();

    return _lazyObject;
}

这将提供相同的IL

public MyLazyObject GetMyLazyObjectUsingNullCoalescingOpMethod()
{
    _lazyObject = _lazyObject ?? new MyLazyObject();

    return _lazyObject;
}

如上所述,它只是语法糖。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM