Как работают делегирование / лямбда-типинг и принуждение? - PullRequest
9 голосов
/ 29 сентября 2010

Я заметил несколько примеров того, что работает и не работает при работе с лямбда-функциями и анонимными делегатами в C #. Что здесь происходит?

class Test : Control {
    void testInvoke() {
        // The best overloaded method match for 'Invoke' has some invalid arguments
        Invoke(doSomething);

        // Cannot convert anonymous method to type 'System.Delegate' because it is not a delegate type
        Invoke(delegate { doSomething(); });

        // OK
        Invoke((Action)doSomething);

        // OK
        Invoke((Action)delegate { doSomething(); });

        // Cannot convert lambda expression to type 'System.Delegate' because it is not a delegate type
        Invoke(() => doSomething());

        // OK
        Invoke((Action)(() => doSomething()));
    }

    void testQueueUserWorkItem() {
        // The best overloaded method match for 'QueueUserWorkItem' has some invalid arguments
        ThreadPool.QueueUserWorkItem(doSomething);

        // OK
        ThreadPool.QueueUserWorkItem(delegate { doSomething(); });

        // The best overloaded method match for 'QueueUserWorkItem' has some invalid arguments
        ThreadPool.QueueUserWorkItem((Action)doSomething);

        // No overload for 'doSomething' matches delegate 'WaitCallback'
        ThreadPool.QueueUserWorkItem((WaitCallback)doSomething);

        // OK
        ThreadPool.QueueUserWorkItem((WaitCallback)delegate { doSomething(); });

        // Delegate 'WaitCallback' does not take '0' arguments
        ThreadPool.QueueUserWorkItem(() => doSomething());

        // OK
        ThreadPool.QueueUserWorkItem(state => doSomething());
    }

    void doSomething() {
        // ...
    }
}

Ну, это много примеров. Я думаю, мои вопросы следующие:

  1. Почему Invoke всегда отказывается от лямбда-функции или анонимного делегата, но ThreadPool.QueueUserWorkItem работает нормально?

  2. Что, черт возьми, делает «Невозможно преобразовать анонимный метод в тип« System.Delegate », потому что это не тип делегата»?

  3. Почему ThreadPool.QueueUserWorkItem принимает анонимного делегата без параметров, но без лямбда-выражения без параметров?

1 Ответ

9 голосов
/ 29 сентября 2010
  1. ThreadPool.QueueUserWorkItem имеет определенного делегата в своей подписи;Invoke просто имеет Delegate.Лямбда-выражения и анонимные методы могут быть преобразованы только в определенный тип делегата.

  2. Это просто плохое сообщение об ошибке.Это означает: «Я не знаю точно, в какой тип делегата вы пытаетесь преобразовать».

  3. Вы используете анонимный метод без списка параметров., который может быть преобразован в любой тип делегата, который не использует параметры out / ref.Если вы попробовали delegate() { ... } (то есть явно пустой список параметров), это не сработало бы.Способность анонимных методов «меня не волнуют параметры» - это функция only , которой обладают лямбда-выражения.

Проще всего продемонстрировать всеоб этом в контексте простых заданий, ИМО:

// Doesn't work: no specific type
Delegate d = () => Console.WriteLine("Bang");

// Fine: we know the exact type to convert to
Action a = () => Console.WriteLine("Yay");

// Doesn't work: EventHandler isn't parameterless; we've specified 0 parameters
EventHandler e1 = () => Console.WriteLine("Bang");
EventHandler e2 = delegate() { Console.WriteLine("Bang again"); };

// Works: we don't care about parameter lists
EventHandler e = delegate { Console.WriteLine("Lambdas can't do this"); };
...