以下に小さなコードサンプルをまとめました(現在はC#3.5ですが、C#4.0で答えが異なるかどうかも知りたいです)
3 つの単純なデリゲートと 3 つの単純な関数があります...ここでは問題ありません。すべてが期待どおりにコンパイルされ、誤ってデリゲート A をメソッド B など (パラメーターの数が間違っている) にリンクしようとするとコンパイルされません。
私が理解するのに苦労しているのは、匿名関数が名前付きデリゲートの 3 つすべてにリンクされて満足しているように見える理由です。
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"));