3

以下の2番目のテストメソッドはコンパイルされません(ラムダ式をターゲットタイプに変換できませんD1)。これは、(非ジェネリック)デリゲートの共変性がラムダ式で機能しないことを意味しますか?

[TestFixture]
public class MyVarianceTests
{
    private abstract class Animal {}
    private class Tiger : Animal {}

    private delegate Type D1(Tiger tiger);

    private static Type M1(Animal animal)
    {
        return animal.GetType();
    }

    [Test]
    public void ContravariantDelegateWithMethod()
    {
        D1 func = M1;
        Type result = func(new Tiger());
        Assert.AreEqual(result, typeof (Tiger));
    }

    [Test]
    public void ContravariantDelegateWithLambda()
    {
        D1 func = (Animal animal) => animal.GetType();
        Type result = func(new Tiger());
        Assert.AreEqual(result, typeof (Tiger));
    }
}
4

2 に答える 2

6

言語の不一致を特定しました。

これは、言語仕様で明示的に呼び出されます。

7.15.1無名関数のシグネチャ

[...]メソッドグループ変換(§6.6)とは対照的に、無名関数パラメータータイプの逆分散はサポートされていません。[...]

...これは問題を提起します:

言語設計者がわざわざこの機能をサポートしなかったのはなぜですか?

<speculation>

明らかに、この機能にはいくつかの小さな利点があります。しかし、それは準拠したコンパイラの実装に必要な余分な複雑さのコストを正当化しますか?

ラムダ式を作成するときは、変換されるデリゲート/式ツリーの型を正確に知っている必要があります任意のラムダを「保持」できる汎用型はありません)。C#5の時点では、ラムダ(メソッドとは対照的に)は、単一のデリゲート/式ツリーインスタンスの作成を支援する以外の目的はまったくありません。したがって、パラメーターに必要なものよりも一般的な型を明示的に指定し、コンパイラーからの逆分散のサポートを期待することには、(利便性以外の)利点はありません。型を完全に省略して、再利用性や表現力を損なうことなく、型推論に依存する(または、最悪の場合、必要な正確なパラメーター型を明示的に指定する)ことができます。

これは明らかに、デリゲート/式ツリーの作成以外の目的に役立つメソッドには適用されません。特定の関数シグニチャ(デリゲートのシグニチャとは異なる)が最も適切であるために必要な場合や、インターフェイスコントラクトを満たす必要があるために必要な場合があります。さらに、メソッドグループ変換を実行しているときに、(デリゲート/式ツリーを作成するプログラマーとして)問題のメソッドを必ずしも「所有」しているとは限らないことを考慮してください(サードパーティのアセンブリにある可能性があります)。これはラムダには当てはまりません。

言語設計者は、メソッドグループの場合とは異なり、ラムダのパラメーター型の逆分散を実装することの利点はコストを正当化しないと感じたようです。

</speculation>

于 2012-09-01T15:35:09.903 に答える
2

D1はタイプTigerの引数を除いていますが、タイプAnimalを渡しています。動物は虎ではありませんが虎は動物です

于 2012-09-01T15:12:02.307 に答える