Когда оцениваются свойства в замыканиях? - PullRequest
7 голосов
/ 28 ноября 2011

Несколько методов в нашей кодовой базе используют «MaybeObject», который может передаваться в функции, когда результат может быть известен, или может полагаться на внешний вызов веб-службы, который еще не был выполнен. Например, указанное ниже свойство может иметь указанное известное значение или, если оно не указано и вызываться после завершения асинхронного вызова, оно возвращает результат асинхронного вызова.

private string _internalString;
public string stringProp
{ 
    get
    {
        if (!string.IsNullOrEmpty(_internalString))
            return _internalString;
        return resultOfAsyncCallFromSomewhereElse;
    }

    set { _internalString = value; }
}

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

Вопрос в том, будет ли в приведенном ниже коде попытка создания лямбды и оценки stringProp (которая еще не может быть заполнена), или оценка будет отложена до тех пор, пока не будет вызвано результирующее действие (которое будет после проверки асинхронная операция завершена)?

public Action ExampleMethod(MaybeObject maybe)
{
    return () => doSomethingWithString(maybe.stringProp);
}

Ответы [ 6 ]

6 голосов
/ 28 ноября 2011

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

() => doSomethingWithString(maybe.stringProp);

Вот даже ссылка maybeможет быть нулевым, и у вас не возникнет никаких проблем, таких как NullReferenceException, до выполнения делегата.Этот прием иногда используется для разрешения значений с поздним связыванием.

Википедия: Закрытие :

Закрытие сохраняет ссылку на среду в то времяон был создан (например, для текущего значения локальной переменной во вложенной области видимости), в то время как общая анонимная функция не должна этого делать.

Хороший обзор спецификаций закрытия C # - Анонимные методы и замыкания в C #

Из определения Closure можно сделать вывод, что Closure запоминает значения переменных во время своего создания.Однако в C # внешняя локальная переменная (в данном случае i) используется совместно с анонимным методом, создавая ее в куче.Это означает, что любое изменение в нем в анонимном методе изменяет исходное значение, и когда метод вызывается во второй раз, он получает измененное значение i как 1 (см. Вторую строку вывода).Это заставляет многих утверждать, что анонимный метод на самом деле не является Замыканием, поскольку по его определению значение переменной во время создания Замыкания следует помнить и не изменять.

3 голосов
/ 28 ноября 2011

Оценка будет отложена до вызова окончательного действия.

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

Например, все эти способы передачи кода для выполнения через делегат Action все эквивалентны, и метод doSomethingWithString не будет выполнен, пока не будет сделан вызов Action():

Явный метод (.NET 1.1):

private MaybeObject maybe;

public Action ExampleMethod()
{
    return new Action(DoSomethingWithMaybeObject);
}

private void DoSomethingWithMaybeObject()
{
    doSomethingWithString(maybe.stringProp)
}

Анонимный метод (.NET 2.0):

public Action ExampleMethod(MaybeObject maybe)
{
    return delegate() { doSomethingWithString(maybe.stringProp) };
}

Лямбда (.NET 3.5):

public Action ExampleMethod(MaybeObject maybe)
{
    return () => doSomethingWithString(maybe.stringProp);
}

Смотри также:

2 голосов
/ 26 сентября 2012

Свойства в замыканиях не оцениваются до тех пор, пока не будет выполнено действие, поскольку свойства являются методами, а не значениями.Доступ к MyObject.MyProperty аналогичен вызову кода MyObject.get_MyProperty (), поэтому вы можете получить другое поведение при использовании свойства по сравнению с базовой переменной.

0 голосов
/ 28 ноября 2011

Вы должны попробовать это сами, чтобы увидеть, что происходит!

В этом случае кажется, что замыкание действительно около MaybeObject, а не только свойства строки (потому что объект передается в Action).Свойство string не доступно до тех пор, пока не будет выполнено действие.

Но даже если сама строка была переменной, переданной замыканию ...

string s = "";
Func<bool> isGood = () => s == "Good"; 

s = "Good";
Console.WriteLine(isGood());

// prints 'True'

Здесь видно, что замыканиесоздается вокруг строки, но не выполняется до выполнения.

Делегаты работают точно так же, как и любая другая функция - на самом деле они ничего не делают, пока не будут вызваны.

0 голосов
/ 28 ноября 2011

это будет отложено.ExampleMethod () возвращает делегата анонимной функции () => doSomethingWithString (Maybe.stringProp), поэтому doSomethingWithString () не будет вызываться до тех пор, пока этот делегат не будет вызван

0 голосов
/ 28 ноября 2011
In .net closures are passed as reference so they are executed as they are evaluated, the same reason you can do something like this.


EventHandler handler = null;
handler = (sender, args) => { // event handler do something};
SomeEvent += handler;
...