简体   繁体   English

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

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

Greetings I was doing some lazy initialization code today, and thought why not use the null-coalescing operator to do this, it is shorter, but then I thought is there any overhead or additional cost to doing it this way. 问候我今天做了一些懒惰的初始化代码,并想到为什么不使用null-coalescing运算符来做这个,它更短,但后来我认为这样做有任何开销或额外成本。

Below is simplified sample code showing a more common form used for lazy initialization, and then one using null-coalescing operator. 下面是简化的示例代码,显示了一个用于延迟初始化的更常见的表单,然后是一个使用null-coalescing运算符的表单。 They have the exact same results, and appear equivalent. 它们具有完全相同的结果,并且看起来相同。 My first thoughts are that after the object has been created there is now an additional assignment of it to itself using ?? 我的第一个想法是,在创建了对象之后,现在有一个额外的赋值给它自己使用?? . Is this a non-issue and the compiler/JIT optimizes this some how, is there something more nefarious going on and you should never do lazy initialization with ?? 这是一个非问题,编译器/ JIT优化了一些如何,是否有更邪恶的事情,你永远不应该做懒惰的初始化?? , or it is perfectly safe and no bad mojo can come from it. ,或者它是完全安全的,没有坏的魔力可以来自它。

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;
}

Yes, a little thing called thread safety. 是的,一个叫做线程安全的小东西。 The two methods you give are functionally equivalent, so the null coalescing operator is not bad in and of itself, but neither of the approaches you've listed is thread-safe, so if two threads try to call your Get method at the same time, you could end up producing two MyLazyObject s. 你给出的两个方法在功能上是等价的,所以null合并运算符本身并不坏,但是你列出的方法都不是线程安全的,所以如果两个线程试图同时调用你的Get方法,你最终可能会产生两个MyLazyObject That may not be a big deal, but it's probably not what you're hoping for. 这可能不是什么大问题,但它可能不是你所希望的。

If you're using .NET 4, just use a Lazy . 如果您使用的是.NET 4,请使用Lazy

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

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

The code is concise, easy to understand, and thread safe. 代码简洁,易于理解,并且线程安全。

It is perfectly safe and well defined - and indeed, it means the compiler can just copy the head of the stack (dup) and store once, rather than store-field, load-field. 它非常安全且定义良好 - 事实上,它意味着编译器可以只复制堆栈的头部(dup)并存储一次,而不是存储字段,load-field。

The only time it is a problem is c# 1.2 (.NET 1.1) where it doesn't exist. 它唯一出现问题的是c#1.2(.NET 1.1),它不存在。

The null coalescing operator in syntactic sugar. 句法糖中的空合并运算符。 Essentially it is the same as your first example, and I don't believe the JIT compiler makes an special optimisations for it. 本质上它与您的第一个示例相同,我不相信JIT编译器对它进行了特殊的优化。 What you should be more concerned with, is the thread-safety of your methods. 你应该更关心的是你的方法的线程安全性。 The null coalescing operator, is not atomic, which means you should ensure that your MyLazyObject is instantiated in a thread-safe manner before returning. null合并运算符不是原子的,这意味着您应该确保在返回之前以线程安全的方式实例化MyLazyObject

You could even alther the code of the first method: 您甚至可以使用第一种方法的代码:

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

    return _lazyObject;
}

This will deliver the same IL as 这将提供相同的IL

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

    return _lazyObject;
}

As said, it's just syntactic sugar. 如上所述,它只是语法糖。

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

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