Подтвердить что ты не робот

Любые веские причины не использовать оператор с нулевым коалесцентом для ленивой инициализации?

Приветствую, что сегодня я делал ленивый код инициализации, и подумал, почему бы не использовать оператор с нулевым коалесцентом для этого, он короче, но тогда я подумал, что есть какие-то накладные расходы или дополнительные затраты для этого.

Ниже приведен упрощенный пример кода, показывающий более общую форму, используемую для ленивой инициализации, а затем с использованием оператора нулевой коалесценции. Они имеют одинаковые результаты и выглядят эквивалентными. Мои первые мысли состоят в том, что после создания объекта теперь есть дополнительное назначение для себя, используя ??. Это не проблема, и компилятор /JIT оптимизирует это как-то, есть ли что-то более гнусное, и вы никогда не должны делать ленивую инициализацию с помощью ??, или это абсолютно безопасно, и от него не может быть плохого mojo.

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

Ответ 1

Да, маленькая вещь называется безопасностью потока. Два метода, которые вы даете, функционально эквивалентны, поэтому оператор нулевой коалесценции сам по себе не плох, но ни один из подходов, которые вы указали, не является потокобезопасным, поэтому, если два потока попытаются вызвать ваш метод Get на В то же время вы можете создать два MyLazyObject s. Это не может быть большой проблемой, но это, вероятно, не то, на что вы надеетесь.

Если вы используете .NET 4, просто используйте Lazy.

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

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

Код является кратким, понятным и безопасным для потоков.

Ответ 2

Это совершенно безопасно и четко определено - и действительно, это означает, что компилятор может просто скопировать голову стека (dup) и сохранить один раз, а не store-field, load-field.

Единственный раз, когда это проблема, - С# 1.2 (.NET 1.1), где он не существует.

Ответ 3

Нулевой коалесцирующий оператор в синтаксическом сахаре. По сути, это то же самое, что и ваш первый пример, и я не верю, что компилятор JIT делает для него специальные оптимизации. То, что вас больше беспокоит, - это безопасность потоков ваших методов. Оператор нулевого коалесцирования не является атомарным, что означает, что вы должны убедиться, что ваш MyLazyObject создается поточно-безопасным способом перед возвратом.

Ответ 4

Вы даже можете добавить код первого метода:

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

    return _lazyObject;
}

Это приведет к тому же IL, что и

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

    return _lazyObject;
}

Как сказано, это просто синтаксический сахар.