Ответ 1
Причина в следующем:
Как вы объявляете делегата, он указывает непосредственно на метод ToString
для статического экземпляра int. Он захватывается во время создания.
Как отмечает Флиндеберг в комментариях ниже, у каждого делегата есть цель и метод, который должен быть выполнен на цели.
В этом случае метод, который должен быть выполнен, является, очевидно, способом ToString
. Интересной частью является экземпляр, в котором выполняется метод: Это экземпляр I
во время создания, то есть делегат не использует I
, чтобы использовать экземпляр, но он сохраняет ссылку на сам экземпляр.
Позже вы меняете I
на другое значение, в основном присваивая ему новый экземпляр. Это не волшебным образом изменяет экземпляр, захваченный в вашем делегате, почему это должно быть?
Чтобы получить ожидаемый результат, вам нужно будет изменить делегат:
static Func<string> del = new Func<string>(() => I.ToString());
Подобным образом делегат указывает на анонимный метод, который выполняет ToString
в текущем I
во время выполнения делегата.
В этом случае метод, который должен быть выполнен, представляет собой анонимный метод, созданный в классе, в котором объявлен делегат. Экземпляр является нулевым, поскольку он является статическим методом.
Посмотрите на код, который компилятор создает для второй версии делегата:
private static Func<string> del = new Func<string>(UserQuery.<.cctor>b__0);
private static string cctor>b__0()
{
return UserQuery.I.ToString();
}
Как вы можете видеть, это обычный метод, который что-то делает. В нашем случае он возвращает результат вызова ToString
в текущем экземпляре I
.