2

TL;DR

元のプロパティの派生型を返すように宣言を変更できるように、インターフェイスでプロパティを非表示にすることの何が問題になっていますか?

これは以前に尋ねられたにちがいないと確信していますが、見つけることができず、長い質問をお詫びします。

この状況があるとします:

public interface A
{
    B TheB{get;}
}

public interface MoreSpecificA : A
{
    MoreSpecificB TheMoreSpecificB{get;}
}

public interface B{...}

public interface MoreSpecificB:B{...}

MoreSpecificAのユーザーが である B にアクセスできるようにしたいと思いますMoreSpecificB。呼び出しTheBてキャストするか、メソッドを呼び出すことでこれを行うことができますTheMoreSpecificBMoreSpecificA次のように宣言することもできます。

public interface MoreSpecificA : A
{
    new MoreSpecificB TheB{get;}
}

これで、同じメソッドを使用してMoreSpecificB.

を使用しnewてメソッドを非表示にすると歯が立たなくなりますが、なぜこれが悪い考えなのですか? ここで行うのは合理的なことのようです。

これについて私が見たほとんどの場合の一般的な提案は、代わりにジェネリックを使用することのようですが、これには問題があるようですMoreSpecificA。インスタンスにアクセスするときにあいまいさを与える拡張を行うには、A必要MoreSpecificAかどうかがわからないためですATheBMoreSpecificAA.TheBMoreSpecificA.TheB

public interface ABase<T> where T : B
{
    T TheB{get;}
}

public interface A : ABase<B>
{        
}

public interface MoreSpecificA : ABase<MoreSpecificB>,A
{        
}

public class blah
{
    public A GetA(MoreSpecificA specificA)
    {
        return specificA; //can't do this unless MoreSpecificA extends A 
    }

    public B GetB(MoreSpecificA specificA)
    {
        return specificA.TheB; //compiler complains about ambiguity here, if MoreSpcificA extends A
    }
}

これは、MoreSpecificA で新しい TheB を宣言することで解決できます (ただし、再び新しい問題が発生します)。

MoreSpecificA が A を拡張しない場合、blah上記のクラスの最初のメソッドは、MoreSpcificA を A に変換できないため、エラーになります。

これを書いているときに、 BaseA を次のように反変であると宣言すると、次のようになることに気付きました。

public interface ABase<out T> where T : B
{
    T TheB{get;}
}

そして私のクラスは

public class blah
{
    public ABase<B> GetA(MoreSpecificA specificA)
    {
        return specificA; 
    }

    public B GetB(MoreSpecificA specificA)
    {
        return specificA.TheB; //compiler complains about ambiguity here
    }
}

それから私は両方の長所を得る. このソリューションの適用可能性は、Aに何かを追加するかどうかによって異なりますABaseか?

それとも、元のメソッドの派生型を返すために派生型のメソッドを非表示にするという当初の計画は大丈夫ですか?

4

1 に答える 1

2

それとも、元のメソッドの派生型を返すために派生型のメソッドを非表示にするという当初の計画は大丈夫ですか?

全く同じ意味なら大丈夫だと思います。たとえば、標準ライブラリでこのようなものを見ることができIDbConnection.CreateCommandます。IDbCommandSqlConnection.CreateCommandSqlCommand

その場合、IDbConnectionバージョンの明示的なインターフェイス実装を使用していますが、同じ原則です。

IEnumerator<T>.CurrentvsIEnumerator.CurrentIEnumerable<T>.GetEnumerator()vsでも見ることができますIEnumerable.GetEnumerator()

より弱く型付けされたメソッドの実装がより強く型付けされたメソッドを呼び出した結果を返す場合にのみ使用しますが、暗黙的な変換を使用します。彼らが実際に別のことをし始めると、後でそれを推論するのがはるかに難しくなります.

于 2012-03-20T08:11:07.223 に答える