IEnumerableを超える型推論
-
11-09-2019 - |
質問
この種のものが、まったく同じではないについて、既にスタックオーバーフローのいくつかの記事があります。
なぜこれが動作しません。
public class MyBase { }
public class MyUtils
{
public bool Foo<T> (T myObject) { return true; }
public bool Foo (MyBase myBaseObject) { return false; }
public void Go<T> (IEnumerable<T> items)
{
foreach (var item in items)
{
// this test fails
Assert.IsFalse (Foo (item));
}
}
}
Iは、上記移動()を呼び出すとMyBaseオブジェクトの負荷に渡す場合、、fooへの各呼び出しがtrueを返すジェネリックはFoo()をコールします。
new MyUtils ().Go (new MyBase[] { new MyBase (), new MyBase () });
なぜそれは代わりに、特殊なMyBaseバージョンを呼び出すことはありませんか?私は直接はFoo(新しいMyBaseを())を呼び出した場合は、それを正しく行うために呼んで推測します。これは、C#3内のコレクションのための共分散の欠如である、または私はちょうど愚かさと正確にこれをやっていないのですか?
ありがとうございます。
アイザック
解決
Go
機能がある)プログラムがあるときに呼び出すためにどの方法chosesがあるため、これは、「専門的な」ものを呼び出さないのコンパイルを、のありませんのそれは実行しています。
コンパイラはGo
機能をコンパイルした場合、、それが持っている唯一の情報は、型T
のいくつかのオブジェクトがあるということです。それはあなたが時間内にいくつかの後の時点で型MyBase
のオブジェクトでそれを供給することができる任意のアイデアを持っていません。それが持っている唯一のオプションはFoo<T>
の過負荷を選択することであり、それはそれでコンパイルされたプログラムに焼くます。
、それは、「ダイナミックディスパッチ」と呼ばれています、とだけなRubyなどの動的言語で使用されていますなどのPython、PHP、
C#3が完全に静的であり、これをサポートしていません。あなたはこのように動作することを望んでいた場合は種類を確認するためにあなたのコードにif文を記述する必要があると思います。 一方、C#4は、いくつかの動的サポートを有しています。あなたはC#4でこのコードを書いていた場合は、次のように、あなたは「GO」関数を宣言できます:
public void Go<T> (IEnumerable<dynamic> items)
そして、それが呼び出された過負荷を選択し、実行時に動的ディスパッチを使用して、
MyBase
を取るために専門のオーバーロードを呼び出します 他のヒント
C#の仕様(7.4.3.2)によれば、非ジェネリックメソッドは、一般的なものよりも優れているので、選択されるべきである。
それは、一般的な呼び出しコンテキスト(「foreachの」ループ)内で呼び出されるので、しかし、私が思うに、一般的なものが、あなたのケースでピックアップされます。