Ниже я собрал небольшой пример кода (в настоящее время в C # 3.5, но также хотел бы знать, отличается ли ответ в C # 4.0)
У меня есть три простых делегата и три простые функции ... Здесь нет проблем, все компилируется, как ожидается, и не будет компилироваться, если я случайно попытаюсь связать делегата A с методом B и т. Д. (Неверное количество параметров).
Я пытаюсь понять, почему анонимные функции кажутся счастливыми быть связанными со всеми тремя именованными делегатами
public class Foo
{
public delegate void del_TestWithNoParams();
public delegate void del_TestWithThreeInts(int x, int y, int z);
public delegate void del_TestWithIntPtr(IntPtr ptr);
public void DoStuff()
{
//All OK so Far ... Code will not compile if I mix these up
del_TestWithNoParams d1 =
TestWithNoParams; d1();
del_TestWithThreeInts d2 =
TestWithThreeInts; d2(2, 4, 8);
del_TestWithIntPtr d3 =
TestWithIntPtr; d3(new IntPtr(0x1234567));
//Why do these compile
del_TestWithNoParams d4_nocompile =
delegate { Console.WriteLine("AnonymousDel d4"); };
del_TestWithThreeInts d5_nocompile =
delegate { Console.WriteLine("AnonymousDel d5"); };
del_TestWithIntPtr d6_nocompile =
delegate { Console.WriteLine("AnonymousDel d6"); };
// Edit 1 goes here
}
public void TestWithNoParams()
{ Console.WriteLine("NoParams"); }
public void TestWithThreeInts(int x, int y, int z)
{ Console.WriteLine("Ints: {0},{1},{2}", x, y, z); }
public void TestWithIntPtr(IntPtr ptr)
{ Console.WriteLine("IntPtr: 0x{0:X8}", ptr.ToInt32()); }
}
Также (просто чтобы дать вам полное работоспособное приложение ...)
static void Main(string[] args)
{
var f = new Foo();
f.DoStuff();
Console.WriteLine("Done"); Console.ReadLine();
}
Редактировать 1: Использование лямбда-методов
//This work as expected - and fail to build if I get the parameter-count wrong.
del_TestWithNoParams d7 =
(() => Console.WriteLine("Lambda NoParams"));
del_TestWithThreeInts d8 =
((a, b, c) => Console.WriteLine("Lambda Ints: {0},{1},{2}", a, b, c));
del_TestWithIntPtr d9 =
((ptr) => Console.WriteLine("Lambda IntPtr: 0x{0:X8}", ptr.ToInt32()));
Test(d7, d8, d9);
Простая вспомогательная функция:
private void Test(del_TestWithNoParams del_A, del_TestWithThreeInts del_B, del_TestWithIntPtr del_C)
{
del_A();
del_B(2, 4, 8);
del_C(new IntPtr(0x1234567));
}
... Согласитесь ли вы, что это лучший метод для написания того же кода ???
Редактировать # 2 - Сводка ответов
Я понимаю, что (каким бы образом я ни писал код), сгенерированный байт-код IL по-прежнему является типобезопасным.
Как и во многих вещах в C #, именованные делегаты, анонимные делегаты и лямбда-методы имеют свое место, и существует баланс между "читаемостью кода", "расширением кода компилятора" и пригодностью для написания индивидуальной заявки.
Ответы ниже помогли ответить на вопрос и показать, что компилятор действительно делает что-то похожее на следующее.
1 - Это НЕ позволит мне сделать эту ошибку
//del_TestWithIntPtr d_mistake_A =
// delegate(int x,int y,int z) { Console.WriteLine(x + y + z); };
2 - «Компилятор, определяющий типы» расширяет делегат (например, d5_nocompile) до
del_TestWithThreeInts d_clearer_3P =
delegate(int x, int y, int z) { Console.WriteLine(x + y + z); };
3 - ВОЗМОЖНО совершить ошибку (все еще действительный код)
del_TestWithThreeInts d_EasyToMakeMistake =
delegate { Console.WriteLine("Oops - forgot to do anything with params"); };
// (this is really :- delegate (int x, int y, int z) {...} )
4 - Однако, когда перезаписывается как лямбда-выражение, это становится немного более очевидным при просмотре кода позже (или другому разработчику)
del_TestWithThreeInts d_LessEasyToMakeMistake =
((x, y, z) => Console.WriteLine("Still POSSIBLE to make mistake, but more obvious"));