19

IEnumerable<T>インターフェースの例:

public interface IEnumerable<out T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

このインターフェイスでは、ジェネリック型はインターフェイス メソッドの戻り値の型としてのみ使用され、メソッド引数の型としては使用されないため、共変になる可能性があります。これを考えると、コンパイラは理論的にインターフェイスからの差異を推測できませんか? 可能であれば、C# で co/contravariance キーワードを明示的に設定する必要があるのはなぜですか。

更新:Jon Skeet が言及したように、この質問はサブ質問になります。

  1. コンパイラは、現在のジェネリック型とそのすべての基本型の中でどのように使用されているかによって、ジェネリック型の相互/反変性を推測できますか?

    たとえば、.NET Framework 4.0 のジェネリック インターフェイス パラメーターのうち、あいまいさなしに共変/反変として自動的にマークできるものはいくつありますか? 約70%、80%、90%、または100%?

  2. 可能であれば、デフォルトでジェネリック型に共/反変性を適用する必要がありますか? 少なくとも、型の使用法から共変/反変を分析および推測できる型に対して。

4

2 に答える 2

16

さて、ここで 2 つの質問があります。まず、コンパイラは常にそうすることができますか? 第二に、そうすべきか(可能であれば)?

最初の質問については、C# in Depth の第 2 版でまさにこの問題を取り上げたときにこのコメントをした Eric Lippert に任せます。

そうしたかったとしても、合理的にできるかどうかは私には明らかではありません。プログラム内のすべてのインターフェースの高価なグローバル分析を必要とする状況を簡単に思いつくことができ <in T, out U>ます<out T, in U>。パフォーマンスが悪く、あいまいなケースの両方があるため、これはありそうもない機能です。

(エリックがこの言葉をそのまま引用してもかまわないことを願っています。彼は以前、そのような洞察を共有することに非常に長けていたので、過去形で説明します :)

一方で、曖昧さなく推測できるケースもまだあるのではないかと思うので、2点目はまだ妥当なのですが…。

コンパイラーが一方向でのみ有効であることを明確に認識できる場合でも、自動化する必要はないと思います。インターフェースの拡張は常にある程度の重大な変更ですが、それを実装しているのがあなただけである場合、一般的にはそうではありません。ただし、人々があなたのインターフェースがバリアントであることに依存している場合、クライアントを壊さずにメソッドを追加することはできないかもしれません...たとえ彼らが実装者ではなく単なる呼び出し元であっても。追加するメソッドによって、以前は共変だったインターフェイスが不変になる可能性があります。その時点で、それを共変的に使用しようとしている呼び出し元を中断できます。

基本的に、これを明示的に要求することは問題ないと思います。これは、考えずに誤って共分散/反分散になってしまうのではなく、意識的に行うべき設計上の決定です。

于 2010-08-30T19:14:52.680 に答える
5

この記事では、コンパイラが推測できない状況があることを説明しているため、明示的な構文を提供します。

interface IReadWriteBase<T>
{
    IReadWrite<T> ReadWrite();
}

interface IReadWrite<T> : IReadWriteBase<T>
{

}

ここで何を推測しますinout、どちらも機能しますか?

于 2010-08-30T19:18:37.947 に答える