Не могли бы вы помочь мне в понимании делегатов в языке C # и .NET Framework? Я пытался проверить код и обнаружил, что полученные результаты были для меня неожиданными. Вот:
class Program
{
public static int I = 0;
static Func<string> del = new Func<string>(I.ToString);
static void Main(string[] args)
{
I = 10;
Console.WriteLine("{0}", del());
}
}
Ответ был 0, но не 10. Почему?
()
вызоветToString
.Func
s, это было предположение :)static
метод. Когда он представляет метод экземпляра, делегат содержит как «целевой» объект, для которого следует вызвать метод, так и информацию о методе. Итак, когда вы говоритеdel = I.ToString;
, онdel
будет содержать объект,I
который здесьInt32
(неизменяемый тип значения). Когда вы используете анонимную функцию,del = () => I.ToString();
компилятор создает метод,static string xxx() { return I.ToString(); }
аdel
объект содержит этот сгенерированный метод.Ответы:
Причина в следующем:
То, как вы объявляете делегат, указывает непосредственно на
ToString
метод статического экземпляра int. Он зафиксирован во время создания.Как указывает Флиндеберг в комментариях ниже, у каждого делегата есть цель и метод, который должен выполняться на цели.
В этом случае очевидно, что выполняемый
ToString
метод - это метод. Интересной частью является экземпляр, на котором выполняется метод: это экземплярI
во время создания, а это означает, что делегат не используетI
экземпляр для использования, но сохраняет ссылку на сам экземпляр.Позже вы измените
I
значение, присвоив ему новый экземпляр. Это не меняет волшебным образом экземпляр, захваченный в вашем делегате, зачем это нужно?Чтобы получить ожидаемый результат, вам нужно будет изменить делегата на это:
static Func<string> del = new Func<string>(() => I.ToString());
Таким образом, делегат указывает на анонимный метод, который выполняется
ToString
в текущем состоянииI
во время выполнения делегата.В этом случае выполняемый метод - это анонимный метод, созданный в классе, в котором объявлен делегат. Экземпляр имеет значение null, поскольку это статический метод.
Взгляните на код, который компилятор генерирует для второй версии делегата:
private static Func<string> del = new Func<string>(UserQuery.<.cctor>b__0); private static string cctor>b__0() { return UserQuery.I.ToString(); }
Как видите, это нормальный метод, который что- то делает . В нашем случае он возвращает результат вызова
ToString
текущего экземпляраI
.источник
Вам необходимо перейти
I
к своей функции, чтобы ееI.ToString()
можно было выполнить в подходящее время (вместо того, чтобы создавать функцию во время).class Program { public static int I = 0; static Func<int, string> del = num => num.ToString(); static void Main(string[] args) { I = 10; Console.WriteLine("{0}", del(I)); } }
источник
Вот как это нужно делать:
using System; namespace ConsoleApplication1 { class Program { public static int I = 0; static Func<string> del = new Func<string>(() => { return I.ToString(); }); static void Main(string[] args) { I = 10; Console.WriteLine("{0}", del()); } } }
источник
Делегат C # enable инкапсулирует как объект, так и экземпляр, и метод. Объявление делегата определяет класс, производный от класса System.Delegate. Экземпляр делегата инкапсулирует список вызовов, который представляет собой список из одного или нескольких методов, каждый из которых называется вызываемым объектом.
узнать больше формы
http://asp-net-by-parijat.blogspot.in/2015/08/what-is-delegates-in-c-how-to-declare.html
источник
Я предполагаю, что int передаются значениями, а не ссылками, и по этой причине при создании делегата он является делегатом метода ToString текущего значения «I» (0).
источник
Foo
вместоint
и изменили строкуI = 10
на,I = new Foo(10)
вы бы получили тот же результат, что и с текущим кодом.I.Value = 10
это что-то совсем другое. Это не назначает новый экземплярI
. НоI
здесь важно назначить новый экземпляр .