インターフェイス実装分散の壊れていない実装は、戻り値の型で共変であり、引数の型で反変でなければなりません。
例えば:
public interface IFoo
{
object Flurp(Array array);
}
public class GoodFoo : IFoo
{
public int Flurp(Array array) { ... }
}
public class NiceFoo : IFoo
{
public object Flurp(IEnumerable enumerable) { ... }
}
どちらも「新しい」規則の下では合法ですよね?しかし、これはどうですか:
public class QuestionableFoo : IFoo
{
public double Flurp(Array array) { ... }
public object Flurp(IEnumerable enumerable) { ... }
}
ここでは、どの暗黙の実装が優れているかを判断するのは難しいです。最初のものは引数の型と完全に一致しますが、戻り値の型とは一致しません。2 番目は、戻り値の型が完全に一致しますが、引数の型は一致しません。IFoo
インターフェイスを使用する人は誰でもArray
.
そして、これは決して最悪ではありません。代わりにこれを行うとどうなりますか:
public class EvilFoo : IFoo
{
public object Flurp(ICollection collection) { ... }
public object Flurp(ICloneable cloneable) { ... }
}
賞金を獲得するのはどっち?これは完全に有効なオーバーロードですがICollection
、ICloneable
互いに何の関係もなく、Array
両方を実装しています。ここには明らかな解決策はありません。
インターフェイス自体にオーバーロードを追加し始めると、さらに悪化します。
public interface ISuck
{
Stream Munge(ArrayList list);
Stream Munge(Hashtable ht);
string Munge(NameValueCollection nvc);
object Munge(IEnumerable enumerable);
}
public class HateHateHate : ISuck
{
public FileStream Munge(ICollection collection);
public NetworkStream Munge(IEnumerable enumerable);
public MemoryStream Munge(Hashtable ht);
public Stream Munge(ICloneable cloneable);
public object Munge(object o);
public Stream Munge(IDictionary dic);
}
気が狂わずにこの謎を解き明かそうと頑張ってください。
もちろん、インターフェイスの実装が戻り値の型の差異のみをサポートし、引数の型の差異はサポートしないと主張する場合、これはすべて意味がありません。しかし、ほとんどの人は、そのような半分の実装は完全に壊れていると見なし、バグ レポートを大量に送信し始めるので、C# チームがそれを行うとは思いません。
これが今日の C# でサポートされていない公式の理由かどうかはわかりませんが、これは、「書き込み専用」コードの種類の良い例として役立つはずであり、C# チームの設計の一部です。哲学は、開発者がひどいコードを書かないようにすることです。