1

私は、C# デリゲートのこの制限についてかなり興味があります。次のコードはコンパイルされません。

class Program
{
   delegate void Foo(string s);

   static void Main(string[] args)
   {
      Foo f = Test; // Error
      f("Hello");
   }

   static int Test(string s)
   {
      return s.Length;
   }
}

ここでのエラーは、デリゲートFooに戻り値の型がないため、関数への参照を作成するために使用できないことTestです。

しかし、なぜこれが問題なのですか?Test明らかに、デリゲートを介して呼び出す場合f、それらはの戻り値にアクセスできません。これは完全に公平ですが、コンパイラは戻り値を単に無視するだけでタイプセーフなコードTestを生成できるように思えます。そのケースを最適化できること。

明らかに、状況が逆で、 be return とreturn をFoo指定した場合、問題が発生します。したがって、その場合はコンパイラ エラーが発生することに完全に同意します。しかし、デリゲートを暗黙的に一致させることができないのはなぜですか?stringTestvoidint Test(string) void Foo(string)

考えられる 2 つの答えのうちの 1 つを探しています。1 つは、この機能を許可することの論理的な問題です。デリゲートを介してメソッドを呼び出すときに戻り値の型を無視すると、安全でない状態が発生する場合はありますか? または、2 つ目は、この実装が仕様に違反する理由を明確にする C# 仕様への参照です。

4

1 に答える 1

1

C# 仕様 (セクション 15.2 デリゲートの互換性) には、このように記載されていました。

次のすべてが当てはまる場合、メソッドまたはデリゲート M はデリゲート型 D と互換性があります。

...

· M の戻り値の型から D の戻り値の型への同一性または暗黙的な参照変換が存在します。

型と void の間にはこのような変換は存在しないため、仕様では許可されません。

論理的に実行できる可能性は非常に高いかもしれませんが、よくわかりませんが、他の機能と比較して十分なユースケースがなかった可能性があります。そのためのラッパーを自分で作成するのもかなり簡単で、ユース ケースの必要性も少なくなります。

public Action Ignore<T>(Func<T> call)
{
    return () => call();
}
于 2013-09-20T00:32:06.947 に答える