开发者

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

开发者 https://www.devze.com 2023-04-04 11:28 出处:网络
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 t

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.

Below is simplified sample code showing a more common form used for lazy initialization, and then one using null-coalescing operator. They have the exact same results, and appear equivalent. M开发者_运维百科y 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 ??, 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 MyLazyObjects. 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.

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.

The only time it is a problem is c# 1.2 (.NET 1.1) where it doesn't exist.


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. 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.


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

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

    return _lazyObject;
}

As said, it's just syntactic sugar.

0

精彩评论

暂无评论...
验证码 换一张
取 消