2015-11-13 6 views
9

私は最近、ユニットテストのために基本クラスにインタフェースを導入し、奇妙な問題に遭遇しました。これは、最小限の再現性のあるシナリオです:インタフェースの継承とプロパティの隠蔽の問題

interface IBase 
{ 
    string Text { get; } 
} 

interface IChild : IBase 
{ 
} 

class Base : IBase 
{ 
    public string Text { get { return "Base"; }} 
} 

class Child : Base, IChild 
{ 
    public new string Text { get { return "Child"; }} 
} 

static void Main(string[] args) 
{ 
    var child = new Child(); 
    Console.WriteLine(child.Text); // Outputs "Child" 
    Console.WriteLine((child as Base).Text); // Outputs "Base" 
    Console.WriteLine(((child as Base) as IBase).Text); // Outputs "Child" 
} 

最初の2つのConsole.WriteLineコマンドの出力は論理的であるが、私は最後の1の出力を受け入れるに失敗タイプBaseの一時変数を使用した場合、それもChildを出力します。誰でもここで何が起こっているのか説明できますか?

UPDATE

インタフェースIChildを除去することにより、((child as Base) as IBase).Text突然"Base"もたらします。つまり、ChildIBase(直接またはインターフェイスの継承を使用)を実装している限り、結果は"Base"の代わりに"Child"になると私は結論づけています。

他のクラスのメソッドをリファクタリングしてIBaseの代わりにBaseの引数を取ると、これは突然異なる動作になります。 Base

(child as Base)を、あなたはBaseTextフィールドを使用している:

+4

もちろん、この混乱を避ける必要があります。 '新メンバー 'を必要とすることは決して良いことではありません。 –

+0

実際、その 'new'プロパティはデッドコードで例外を投げました。これは、コードが常に基本型を使用していたため使用されていませんでした。ベースインターフェイスを追加すると、死んだコードが生まれました:) –

答えて

9

基本的には、ここにキャスティングされています。それは明らかだ。

しかし、ここで:

(child as Base) as IBaseあなたはChildTextが表示されますを意味し、あなたがIBaseChildをキャストしていることを意味するIBaseに、その後BaseからChildをキャストしています。 asを使用して、基礎となるオブジェクトを変更していません。

従って(child as Base) as IBasechild as IBaseと同じです。

EDIT:

編集の質問はこの答えが正しいという事実は変わりません。 @InBetweenは、Textプロパティの実装がどのように解決されたかを変更しているだけなので、したがって、ChildクラスはIBaseを直接実装しないため、BaseTextがベストマッチとして使用されます。基本的にはファーストクラスの実装を使用していますIBase