4

以下に小さなコードサンプルをまとめました(現在は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"));
4

3 に答える 3

3

いいえ、これにより型チェックが強制されます。デリゲートへの割り当て時に無名関数にパラメーターが指定されていない場合は、既定値が使用されます。

C# 言語仕様 (§6.5) を参照してください。

匿名メソッド式またはラムダ式は、匿名関数として分類されます (§7.14)。式には型がありませんが、互換性のあるデリゲート型または式ツリー型に暗黙的に変換できます。具体的には、デリゲート型 D は、提供される無名関数 F と互換性があります。

  • F に無名関数シグネチャが含まれている場合、D と F は同じ数のパラメーターを持ちます。
  • F に無名関数シグネチャが含まれていない場合、D のパラメーターに out パラメーター修飾子がない限り、D は任意の型のパラメーターを 0 個以上持つことができます。

ソース コードをコンパイルして(フレームワーク 1.1 のセットアップで) Reflectorで開くと、コンパイラが、パラメーター リストを持たない匿名メソッドに既定のパラメーターを自動的に割り当てることがわかります。

 del_TestWithNoParams d4_nocompile = (CS$<>9__CachedAnonymousMethodDelegate40 != null) ? CS$<>9__CachedAnonymousMethodDelegate40 : (CS$<>9__CachedAnonymousMethodDelegate40 = new del_TestWithNoParams(Program.<Main>b__27));
    del_TestWithThreeInts d5_nocompile = (CS$<>9__CachedAnonymousMethodDelegate41 != null) ? CS$<>9__CachedAnonymousMethodDelegate41 : (CS$<>9__CachedAnonymousMethodDelegate41 = new del_TestWithThreeInts(Program.<Main>b__28));
    del_TestWithIntPtr d6_nocompile = (CS$<>9__CachedAnonymousMethodDelegate42 != null) ? CS$<>9__CachedAnonymousMethodDelegate42 : (CS$<>9__CachedAnonymousMethodDelegate42 = new del_TestWithIntPtr(Program.<Main>b__29));

そして b__28(デリゲート del_TestWithThreeInts のメソッド) は次のようになります

[CompilerGenerated]
private static void <Main>b__28(int, int, int)
{
    Console.WriteLine("AnonymousDel d5");
}
于 2010-02-23T07:42:00.547 に答える
1

匿名メソッドを使用すると、デリゲートのパラメーターごとに定義されたプロパティを使用してクラスが作成されます。

パラメータ値を渡さない場合、デフォルトの値が使用されます。

于 2010-02-23T01:11:55.633 に答える
0

キーワードで作成された匿名メソッドのパラメーターを指定しない場合delegate、パラメーターはコンパイラーによって自動的に推測されるため、デリゲート シグネチャが何であるかは関係ありません。

于 2010-02-23T01:12:18.573 に答える