Преобразование анонимной функции - PullRequest
0 голосов
/ 29 января 2019

C # Спецификация языка 6.5 Преобразование анонимной функции гласит:

...

В частности, анонимная функция F совместима с типом делегата Dпри условии:

...

Если F не содержит подпись анонимной функции , то D может иметь ноль или более параметров любого типа, если толькони у одного параметра D нет модификатора параметра out.

Однако следующий код генерирует ошибки.

using System;
namespace DelegateAnonymousFunctionExample
{
    public delegate void D(int i, int b);
    class Program
    {
        static void Main(string[] args)
        {
            // Valid
            D f1 = (int a, int b) =>
            {
                Console.WriteLine("Delegate invoked...");
            };
            f1(3, 4);

            // Error
            D f2 = () =>
            {
                Console.WriteLine("Delegate invoked...");
            };

            Console.ReadKey();
        }
   }
}

Где я ошибся в приведенном выше коде?

Ответы [ 3 ]

0 голосов
/ 29 января 2019

$ 6,5 спецификации, которую вы указали, также говорит:

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

и $ 6.5.1:

Преобразование анонимной функции в тип делегата создает экземпляр делегата, который ссылается на анонимную функцию

Анонимный метод можно просто определить с помощью lambda-Выражение, на самом деле, эти вещи различны.

Лямбда-выражение не имеет типа и может быть безразлично преобразовано в Выражение , используемое в запросе LINQ выражение и анонимное определение метода.

Итак, в случае ошибки лямбда-выражение будет преобразовано в несовместимый экземпляр делегата , который не принимает аргументов.

Цитата из предоставленной вами спецификации говорит о

D f5 = delegate { Console.WriteLine("Delegate invoked..."); };

Это работает, потому что подпись не указана, и она будет автоматически скомпилирована для совместимого делегата.nstance, который принимает (int, int).

«Если F не содержит сигнатуру анонимной функции» означает отсутствие подписи , но лямбда-выражение '() ' означает подпись, которая не принимает аргументов .И лямбда не может быть объявлена ​​без подписи, как указано в ответе @ Johnny.О примерах делегатов: посмотрите на 4-й пример в примере кода - он недопустим, потому что имеет несовместимую подпись, которая не принимает аргументов, 5-й пример не имеет подписи и он действителен.

Вы также можете скопировать пример ниже ипроверьте, как он будет скомпилирован (просто закомментируйте неверный код ранее) https://sharplab.io/

public delegate void D(int i, int b);

public void Main(string[] args) 
{        
    //valid, lambda expression will be converted to compatible delegate instance
    D f1 = (int a, int b) => Console.WriteLine("Delegate invoked...");
    f1(3, 4);

    //INVALID, lambda expression will be converted to incompatible delegate instance
    D f2 = () => Console.WriteLine("Delegate invoked...");
    f2(3, 4);

    //valid, assigning delegate with compatible signature
    D f3 = delegate(int i, int j) { Console.WriteLine("Delegate invoked..."); };
    f3(3, 4);

    //INVALID, assigning delegate with incompatible signature
    D f4 = delegate() { Console.WriteLine("Delegate invoked..."); };
    f4(3, 4);

    //valid, it will be automatically compiled to compatible delegate instance which accepts (int, int)
    D f5 = delegate { Console.WriteLine("Delegate invoked..."); };
    f5(3, 4);
}
0 голосов
/ 29 января 2019

Делегат - это тип, представляющий ссылки на методы с определенным списком параметров и типом возвращаемого значения

В принципе все начинается с delegate, и в нем указано определенный параметрlist и возвращаемый тип .

Если F не содержит сигнатуру анонимной функции, то D может иметь ноль или более параметров любого типа, если толькони у одного параметра D нет модификатора параметра out.

Анонимный метод может быть объявлен с использованием синтаксиса delegate список параметров { список операторов }.Здесь вы можете опустить список параметров в том случае, если вышеупомянутое говорит, что действует.С другой стороны, если вы задаете параметры, тип параметров должен точно совпадать.

public delegate void MyDelegate(int a);

MyDelegate d = delegate { }; //valid
MyDelegate d = delegate(int a) { }; //valid
MyDelegate d = delegate(int a, int b) { }; //invalid

public delegate void MyDelegateOut(int a, out int b);
MyDelegateOut d = delegate { }; //invalid

Если вы хотите объявить delegate с использованием лямбды, эффект пропуска не может быть заархивирован, так как синтаксис ( входные параметры ) => { список операторов }

0 голосов
/ 29 января 2019

Переменная f2 не получает действительную сигнатуру метода, делегат D ожидает 2 параметра.

...