Как работают делегирование / лямбда-типинг и принуждение?
Я заметил несколько примеров того, что работает и не работает при работе с лямбда-функциями и анонимными делегатами в 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() {
// ...
}
}
Ну, это много примеров. Я думаю, мои вопросы следующие:
Почему
Invoke
всегда отказываются от лямбда-функции или анонимного делегата, ноThreadPool.QueueUserWorkItem
просто отлично?Что, черт возьми, означает "Невозможно преобразовать анонимный метод в тип" System.Delegate ", потому что это не тип делегата"?
Почему
ThreadPool.QueueUserWorkItem
принять анонимный делегат без параметров, но не лямбда-выражение без параметров?
1 ответ
ThreadPool.QueueUserWorkItem
имеет конкретного делегата в своей подписи; Вызвать только чтоDelegate
, Лямбда-выражения и анонимные методы могут быть преобразованы только в определенный тип делегата.Это просто плохое сообщение об ошибке. Это означает: "Я не знаю точно, к какому типу делегата вы пытаетесь преобразовать".
Вы используете анонимный метод без списка параметров, который можно преобразовать в любой тип делегата, который не использует параметры out/ref. Если вы пытались
delegate() { ... }
(то есть явно пустой список параметров), тогда это не будет работать. Эта способность анонимных методов "мне наплевать на параметры" - единственная функция, которой обладают лямбда-выражения.
Проще всего продемонстрировать все это в контексте простых заданий, IMO:
// 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"); };