まず、.NETはとのString
両方IConvertible
であることを忘れないでICloneable
ください。
ここで、次の非常に単純なコードについて考えてみます。
//contravariance "in"
interface ICanEat<in T> where T : class
{
void Eat(T food);
}
class HungryWolf : ICanEat<ICloneable>, ICanEat<IConvertible>
{
public void Eat(IConvertible convertibleFood)
{
Console.WriteLine("This wolf ate your CONVERTIBLE object!");
}
public void Eat(ICloneable cloneableFood)
{
Console.WriteLine("This wolf ate your CLONEABLE object!");
}
}
次に、次のことを試してください(いくつかの方法の中で):
ICanEat<string> wolf = new HungryWolf();
wolf.Eat("sheep");
これをコンパイルしても、コンパイラエラーや警告は表示されません。class
実行すると、呼び出されるメソッドは、の宣言内のインターフェイスリストの順序に依存しているように見えますHungryWolf
。(コンマ(,
)で区切られたリストの2つのインターフェイスを交換してみてください。)
質問は単純です:これはコンパイル時の警告を与える(または実行時にスローする)べきではありませんか?
私はおそらくこのようなコードを思いついた最初の人ではありません。インターフェースの共変性を使用しましたが、インターフェースの共変性を使用して完全に類似した例を作成できます。そして実際、リッパート氏はずっと前にそれをしました。彼のブログのコメントでは、ほとんどの人がそれがエラーであるべきだということに同意しています。しかし、彼らはこれを黙って許可します。なんで?
---
拡張された質問:
上記では、aが(インターフェイス)と(インターフェイス)のString
両方であることを利用しました。これらの2つのインターフェースはどちらも他方から派生していません。Iconvertible
ICloneable
これが、ある意味で少し悪い基本クラスの例です。
aは(直接基本クラス)と(基本クラスの基本クラス)のStackOverflowException
両方であることに注意してください。次に(以前の場合):SystemException
Exception
ICanEat<>
class Wolf2 : ICanEat<Exception>, ICanEat<SystemException> // also try reversing the interface order here
{
public void Eat(SystemException systemExceptionFood)
{
Console.WriteLine("This wolf ate your SYSTEM EXCEPTION object!");
}
public void Eat(Exception exceptionFood)
{
Console.WriteLine("This wolf ate your EXCEPTION object!");
}
}
それをテストします:
static void Main()
{
var w2 = new Wolf2();
w2.Eat(new StackOverflowException()); // OK, one overload is more "specific" than the other
ICanEat<StackOverflowException> w2Soe = w2; // Contravariance
w2Soe.Eat(new StackOverflowException()); // Depends on interface order in Wolf2
}
それでも警告、エラー、例外はありません。class
それでも、宣言のインターフェイスリストの順序に依存します。しかし、私がもっと悪いと思う理由は、今回は、過負荷SystemException
の解決が単なるよりも具体的であるため、常に選択するだろうと誰かが考えるかもしれないからException
です。
バウンティが開かれる前のステータス:2人のユーザーからの3つの回答。
バウンティ最終日のステータス:まだ新しい回答はありません。答えが表示されない場合、私はイスラム教徒のベン・ダウに賞金を授与する必要があります。