Рассмотрим этот фрагмент кода и попытаться угадать, что y1
и y2
вычислятьсяПочему эти две функции не возвращают одно и то же значение?
static class Extensions
{
public static Func<T> AsDelegate<T>(this T value)
{
return() => value;
}
}
class Program
{
static void Main(string[] args)
{
new Program();
}
Program()
{
double x = Math.PI;
Func<double> ff = x.AsDelegate();
Func<double> fg =() => x;
x = -Math.PI;
double y1 = ff(); // y1 = 3.141..
double y2 = fg(); // y2 = -3.141..
}
}
Можно сказать -Aha- двойной тип значения и поэтому значение, возвращенное методом расширения является копия из основной x
. Но когда вы меняете это на делегатов классов, результаты все равно разные. Пример:
class Foo
{
public double x;
}
Program()
{
Foo foo = new Foo() { x=1.0 };
Func<Foo> ff = foo.AsDelegate();
Func<Foo> fg =() => foo;
foo = new Foo() { x = -1.0 };
double y1 = ff().x; // y1 = 1.0
double y2 = fg().x; // y2 = -1.0
}
Таким образом, две функции должны возвращать два разных экземпляра одного и того же класса. Интересно, что ff()
несет с собой ссылку на локальную переменную foo
, но fg()
не делает и полагается на то, что в настоящее время находится в области.
Итак, что происходит, когда эти два делегата передаются другим частям кода, которые не имеют видимости для экземпляра foo
? Каким-то образом вопрос о том, кто владеет какой информацией (данными) становится все менее и более ясным, когда методы расширения объединяются с делегатами.
Поклонись этому ответу из-за краткости + прозрачности + формата. – ja72
Meh ... Это a: не привязывает к * значению * ничего (кроме компилятора, генерирует экземпляр класса захвата) и b: не привязывает строго к «x» * вообще * - более четкое да, но я думаю, что, возможно, немного обманчиво из-за этой простоты. (простота хороша) –
@Marc - это подбросить. Я решил сосредоточиться на том, как он кажется пользователю, а не погружаться в способ его реализации. – Bevan