Хорошо, давайте рассмотрим это:
public static MyObject GetMyObject() {
MyObject o = obj;
if(o == null) {
o = new MyObject();
obj = o;
}
return o;
}
Существует только одно return
утверждение. Единственный способ, которым этот метод может произвести возвращаемое значение null
, - это если единственный return
оператор return o
имеет o == null
, равный true
, когда он выполняется.
Если o
равно null
при выполнении return o
, это означает, что мы вышли из блока if
с o
как null
. Единственный способ, которым мы можем выйти из блока o
с o
как null
, это если o == null
был true
, когда проверялось условное значение для блока if
(если o == null
равно false
, тогда o != null
имеет значение true, и поскольку o
является локальной переменной, на него не может влиять никакой другой поток. Но тогда o == null
, будучи true
, подразумевает, что мы окажемся внутри блока if
и теперь, когда конструктор вызов o = new MyObject()
возвращает, мы гарантируем, что o
не является null
. Второй оператор в блоке if
, obj = o
, не влияет на значение o
. Опять же, поскольку o
локальная переменная, не имеет значения, если через этот путь к коду записано несколько потоков: каждый поток имеет свой собственный o
, и ни один другой поток не может касаться любого другого потока o
.
Поэтому, независимо от того, o == null
равен true
или false
, мы получим o == null
, равную false
, когда блок if
завершится.
Следовательно, этот метод гарантированно возвращает ненулевое значение.
Я просто хочу убедиться, что безопасно предположить, что GetMyObject () никогда не вернет ноль.
Ну, хорошо, если это все, что тебя волнует. Но давайте проясним кое о чем. Ваш метод НЕ является потокобезопасным. Вполне возможно, что будут созданы два экземпляра MyObject
, и два разных вызывающих абонента могут в конечном итоге увидеть разные возвращаемые значения, даже если ясно, что вы намерены иметь только один. Чтобы это исправить, я рекомендую просто использовать Lazy<T>
:
private static Lazy<MyObject> obj;
static Foo() {
obj = new Lazy<MyObject>(
() => new MyObject(),
true
);
}
public static MyObject GetMyObject() {
return obj.Value;
}
public static void ClearMyObject() {
obj = new Lazy<MyObject>(
() => new MyObject(),
true
);
}