ジェネリック型がC#4.0のCoまたはContraバリアントであることを示すために、outまたはinパラメーターを追加する必要がある理由を誰かが説明できますか?
私はこれがなぜ重要なのか、そしてなぜコンパイラーがそれを理解できないのかを理解しようとしてきました。
ありがとう、
ジョシュ
ジェネリック型がC#4.0のCoまたはContraバリアントであることを示すために、outまたはinパラメーターを追加する必要がある理由を誰かが説明できますか?
私はこれがなぜ重要なのか、そしてなぜコンパイラーがそれを理解できないのかを理解しようとしてきました。
ありがとう、
ジョシュ
言語に取り組んでいる Eric Lippert は、関連する問題を明確にするのに役立つ一連の投稿を msdn に投稿しています
。
そのリンクに示されている記事を読むときは、一番下から始めて上に進んでください。
実際にはそれらは必要ありません。abstract
クラスまたはその両方out
で必要になる以上ref
です。それらが存在するのは、私たちプログラマーが自分たちの意図を明確にし、メンテナンス プログラマーが何をしているのかを理解し、コンパイラーがそれを正しく行っていることを確認できるようにするためです。
さて、主な問題は、次のようなクラス階層がある場合です。
class Foo { .. }
class Bar : Foo { .. }
そして、あなたはそれを持っています、それが完全に安全でIEnumerator<Bar>
あるとしても、あなたはそれを使うことはできません。IEnumerator<Foo>
3.5では、これにより多くの痛みを伴う回転が強制されます。この操作は常に安全ですが、ジェネリック型パラメーターの共変使用について知らないため、型システムによって拒否されます。IEnumerator<Bar>
のみを返すことができBar
、すべてBar
がFoo
です。
同様に、があれば、一方または両方がである場合でもIEqualityComparer<Foo>
、型のオブジェクトの任意のペアを比較するために使用できますが、ジェネリック型パラメーターの逆変の使用について知らないため、にキャストすることはできません。タイプのオブジェクトのみを消費し、すべてがです。Foo
Bar
IEqualityComparer<Bar>
IEqualityComparer<Foo>
Foo
Bar
Foo
これらのキーワードがないと、一般的な引数がメソッドへの引数とメソッドの結果タイプの両方として発生する可能性があると想定する必要があるため、上記の変換のいずれかを安全に許可することはできません。
それらを使用すると、型システムは、キーワードで示された方向にこれらのインターフェイス間で安全にアップキャストおよびダウンキャストできるようになり、安全を確保するために必要な規律に違反する場合を示すエラーが発生します。
Jon と Joel は両方とも、これに対するかなり完全な回答を提供しましたが、結論として、これらはコンパイラーにとってそれほど必要ではなく、パラメーターの分散を明示的に示すことによって実装の安全性を保証するのに役立つということです。これは、呼び出しサイトと宣言サイトの両方でout
orキーワードを要求するのと非常によく似たパターンに従います。ref
in
andout
キーワードは C# 1.0 以降のキーワードであり、メソッドへのin
- およびout
- パラメーターのコンテキストで使用されてきました。
共分散と反分散は、インターフェイスの実装方法に関する制約です。それらを推測する良い方法はありません-唯一の方法は使用法からだと思います.それは面倒で、最終的には機能しません.