更新: C# 7.3 以降、これは問題ではなくなりました。リリースノートから:
メソッド グループに、型引数が制約を満たさないジェネリック メソッドが含まれている場合、これらのメンバーは候補セットから削除されます。
C# 7.3 以前:
だから私はEric Lippert の 'Constraints are not part of the signature'を読み、オーバーロードの解決後に型制約がチェックされることを仕様が指定していることを理解しましたが、なぜこれがそうでなければならないのかについてはまだ明確ではありません。以下はエリックの例です。
static void Foo<T>(T t) where T : Reptile { }
static void Foo(Animal animal) { }
static void Main()
{
Foo(new Giraffe());
}
オーバーロードの解決 for: が最適なオーバーロード マッチであると推測するため、これはコンパイルされませんFoo(new Giraffe())
がFoo<Giraffe>
、型制約が失敗し、コンパイル時エラーがスローされます。エリックの言葉で:
ここでの原則は、オーバーロードの解決 (およびメソッドの型の推論) であり、引数のリストと各候補メソッドの仮パラメーターのリストとの間で可能な限り一致するものを見つけます。つまり、候補メソッドのシグネチャを調べます。
型制約は署名の一部ではありませんが、なぜできないのでしょうか? 型制約を署名の一部と見なすのが悪い考えであるシナリオには、どのようなものがありますか? 実装が難しい、または不可能ですか?最適なオーバーロードが何らかの理由で呼び出すことができない場合は、2 番目に最適なオーバーロードに静かにフォールバックすることを推奨しているわけではありません。私はそれを嫌います。最適なオーバーロードの選択に影響を与えるために型制約を使用できない理由を理解しようとしています。
私は、C# コンパイラの内部で、オーバーロードの解決のみを目的として (メソッドを完全に書き換えるわけではありません)、次のことを想像しています。
static void Foo<T>(T t) where T : Reptile { }
次のように変換されます:
static void Foo(Reptile t) { }
型制約を仮パラメータ リストに「引き込む」ことができないのはなぜですか? これはどのように署名を悪い方法で変更しますか? 署名を強化するだけのような気がします。次にFoo<Reptile>
、過負荷候補と見なされることはありません。
編集 2:私の質問がとても混乱していたのも不思議ではありません。私は Eric のブログを正しく読んでおらず、間違った例を引用しました。より適切だと思う例を編集しました。また、タイトルをより具体的なものに変更しました。この質問は、最初に想像したほど単純ではないように思えます。おそらく、いくつかの重要な概念が欠けています。これがスタックオーバーフローの資料であるかどうかはわかりません。この質問/ディスカッションを他の場所に移動するのが最善かもしれません.