Хобрук: Ваш путь к мастерству в программировании

Преобразование анонимных функций

Спецификация языка 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();
        }
   }
}

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


  • Можете дать ссылку на эту спецификацию? 29.01.2019
  • microsoft.com/en-us/download/details.aspx? идентификатор=7029. Это ссылка для скачивания, не уверен, что есть онлайн-версия. 29.01.2019
  • В чем ошибка? 29.01.2019
  • @John ''Делегату 'D' не требуется 0 аргументов 29.01.2019

Ответы:


1

Указанная вами спецификация за 6,5 долларов также говорит:

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

и $6.5.1:

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

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

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

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

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

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

Это работает, потому что сигнатура не указана, и она будет автоматически скомпилирована в совместимый экземпляр делегата, который принимает (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);
}
29.01.2019
  • Это странно. В спецификации, если я правильно помню, анонимные функции включают выражения анонимного метода и лямбда-выражения. 29.01.2019
  • Лямбда-выражение на самом деле не имеет типа и может быть неявно преобразовано в выражение или анонимный метод, дайте мне немного времени, я почти нашел причину... 29.01.2019
  • В спецификации используется термин анонимная функция, который может быть анонимным методом или лямбда-выражением. В разделе 6.5 «Анонимные преобразования функций» это четко указано в первом предложении. Поэтому использование лямбда-выражения не должно быть причиной ошибки. Однако ваше рассуждение о том, что это работает, потому что подпись не указана, и она будет автоматически скомпилирована в совместимый экземпляр делегата, который принимает (int, int). imo, является ключом к ответу. Синтаксически просто невозможно написать лямбда-выражение без круглых скобок, наличие которых подразумевает наличие подписи. 29.01.2019
  • @woldmar, так что в этом случае лямбда-выражение исключено. Я принял твой ответ. 29.01.2019
  • @JohnSmithSr., я думаю, что просто Если F не содержит подписи анонимной функции, это означает отсутствие подписи, но лямбда-функция «()» означает подпись, которая не принимает аргументы. Также лямбда не может быть объявлена ​​​​без подписи, как упоминалось в ответе Джонни. О примерах делегатов: взгляните на 4-й пример в примере кода - он недействителен, потому что имеет несовместимую подпись, которая не принимает аргументы, 5-й пример не имеет подписи, и он действителен. 29.01.2019

  • 2

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

    29.01.2019
  • Привет, так как ты интерпретируешь спецификацию? 29.01.2019
  • Можете ли вы объяснить, как это удовлетворяет второй части спецификации, определенной в вопросе? 29.01.2019
  • Это не отвечает на вопрос. ОП должен был спросить то же самое о том, как воспринимать спецификацию. 29.01.2019
  • Интуитивно я бы сказал то же самое. Но, исходя из спецификации, по крайней мере, в моем понимании, это не должно генерировать ошибок. так что есть недоразумение где-то я не знаю. 29.01.2019

  • 3

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

    В принципе все начинается с delegate и говорит список конкретных параметров и тип возвращаемого значения.

    Если 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 с помощью лямбда-выражения, эффект пропуска не может быть заархивирован, так как используется следующий синтаксис (параметры ввода) => { список-операторов }

    29.01.2019
  • спасибо, ваш пост очень помог, особенно последняя часть. 29.01.2019
  • Новые материалы

    Создание кнопочного меню с использованием HTML, CSS и JavaScript
    Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

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

    Классы в JavaScript
    class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

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

    Как построить любой стол
    Я разработчик программного обеспечения. Я люблю делать вещи и всегда любил. Для меня программирование всегда было способом создавать вещи, используя только компьютер и мое воображение...

    Обзор: Машинное обучение: классификация
    Только что закончил третий курс курса 4 часть специализации по машинному обучению . Как и второй курс, он был посвящен низкоуровневой работе алгоритмов машинного обучения. Что касается..

    Разработка расширений Qlik Sense с qExt
    Использование современных инструментов веб-разработки для разработки крутых расширений Вы когда-нибудь хотели кнопку для установки переменной в приложении Qlik Sense? Когда-нибудь просили..