Использование делегатов в C#


в языке 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. Зачем?

5 79

5 ответов:

причина заключается в следующем:

способ объявления делегата он указывает непосредственно на 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# позволяет инкапсулировать как объект, так и экземпляр и метод. Объявление делегата определяет класс, производный от класса System.Делегат. Экземпляр делегата инкапсулирует список вызовов, который представляет собой список одного или нескольких методов, каждый из которых называется вызываемой сущностью.

узнайте больше формы

http://asp-net-by-parijat.blogspot.in/2015/08/what-is-delegates-in-c-how-to-declare.html

Я предполагаю, что int передаются значениями, А не ссылками, и по этой причине при создании делегата это делегат метода ToString текущего значения "I" (0).