2009-09-09 6 views
6

"new"キーワードが派生クラスのメソッドを隠す方法を理解しています。ただし、キーワードを使用するインターフェイスを実装するクラスにはどのような影響がありますか?C#newキーワードを使用してインターフェイスのプロパティを拡張できますか?

この例では、プロパティを読み書きすることでインターフェイスを拡張することにします。

public interface IReadOnly { 

    string Id { 
     get; 
    } 
} 

public interface ICanReadAndWrite : IReadOnly { 

    new string Id { 
     get; 
     set; 
    } 
} 

次に、あなたがこのようなことを行うことができます:

public IReadOnly SomeMethod() { 
    // return an instance of ICanReadAndWrite 
} 

はこの悪いデザインですか? ICanReadAndWriteを実装するクラスに問題が発生しますか?

編集:ここではが、私はこのような何かをしたい場合があります理由の不自然な例です:

は私がIShoppingCartItemReadWriteを返すファクトリクラスを持っていると言います。次に、価格を操作したり、物を変更したりするサービスレイヤーを持つことができます。次に、これらのオブジェクトを、IShoppingCartItemReadOnlyとして、それらを変更しない種類のプレゼンテーションレイヤーに渡すことができます。 (はい、技術的にはに変更できます。これは設計上の質問であり、セキュリティなどはありません)

+0

具体的な例はあまり意味がありません。読み書きができれば、読み込み専用ではありません。 –

+0

IShoppingCartItemReadWriteは変更できますが、IShoppingCartItemReadOnlyへの参照がある場合は、別のものにキャストしない限り読み取り専用です。 – user10789

+0

実際にはそこに「新しい」キーワードが必要ないことに注意してください。 –

答えて

19

特に悪いことではありません。あなたは(これは暗黙的インタフェースを実装する場合プロパティ/書き込み、次いで単一の読み取りの両方のインターフェイスを満たすことができる)実装ができることを認識しなければならない二つの別個の実装提供する:一般的に、ところで

class Test : ICanReadAndWrite { 
    public string Id { 
     get { return "100"; } 
     set { } 
    } 
    string IReadOnly.Id { 
     get { return "10"; } 
    } 
} 

Test t = new Test(); 
Console.WriteLine(t.Id); // prints 100 
Console.WriteLine(((IReadOnly)t).Id); // prints 10 

new継承修飾子は、コンパイラにシャットダウンするように指示する以外は何もしません。「あなたはそのメンバを隠しています」という警告をスローしません。これを省略すると、コンパイルされたコードには何の効果もありません。

+1

コンパイラ警告を消す良い点は!しかし、クラス定義に対してこのようなことをすると、期待しないような振る舞いをする可能性があるため、不平を言っています。この特定のケースでは、私は意図しない行動を考えることはできません。それゆえの質問です。 – user10789

+1

はい。もちろん、警告は理由によるものです。考えられる唯一の難点は、私が答えて言ったように、異なる実装に解決できる2つの異なるメソッドスロットを扱っているという事実です。これは 'new'を使うことの落とし穴です。 'interfaces'では、ほとんど実装されておらず、呼び出し側はメソッドの任意の実装を予期しているのでほとんどの場合有害ではありません。 –

+1

新しいキーワードは、コンパイラを停止させるためのものではありません。「メンバーを無効にしたくない、私の意図はそれをシャドーすることです。私はその事実を認識しています。この警告は、あなたを「意図せずにメンバーを隠す」ことを防ぐことです。 –

0

コンパイルするかどうかはわかりませんが、推奨するパターンではありません。明示的なインターフェイスの実装を行うことができるため、理論上はIdプロパティのIReadOnlyICanReadAndWrite versiondの2つの全く異なる実装を提供できます。 ICanReadAndWriteインターフェースを変更することを検討してください。プロパティーを置き換えるのではなく、プロパティーにsetterメソッドを追加してください。

+0

間違いなくコンパイルします。新しいキーワードを追加しないと、次のコンパイル警告が表示されます。 'ICanReadAndWrite.Id'は、継承されたメンバー 'IReadOnly.Id'を非表示にします。隠れが意図されていた場合は、新しいキーワードを使用してください。 – user10789

+0

明示的なインターフェイスの実装に関しては、そうするならば、Idプロパティの全く異なる2つの実装がまさにあなたが望むものであると仮定します。 私は、このアプローチによって引き起こされるかもしれない隠された問題点やあまり明白でない問題にもっと興味があります。 – user10789

+1

残念ながら、単にプロパティにセッターを追加するだけでは機能しません。セッターがゲッターをシャドーする場合、プロパティーを読み取るには、シャドウされていないゲッターを持つタイプへの型変換が必要です。セッターがゲッターをシャドーしない場合、つまり、独立ゲッターとセッターが両方ともスコープ内にある場合、どちらもC#またはvb.net内で使用できません。 – supercat

1

ICanReadAndWriteインターフェイスを実装するクラスの意味は、ICeadReadAndWriteインターフェイスで実装されているIReadOnlyとして扱うとICanReadAndWriteインターフェイスとして実装することができます。

0

あなたはそれを行うことができますが、私はあなたがそれを行うことで何を達成したいのか分かりません。

public IReadOnly SomeMethod() { 
    // return an instance of ICanReadAndWrite 
} 

この方法では、あなたがICanReadAndWriteに戻ってきたということは問題でないことを意味IReadOnlyへの参照を返します。このアプローチは良くないでしょうか?

public interface IReadOnly 
{ 
    String GetId(); 
} 

public interface ICanReadAndWrite : IReadOnly 
{ 
    String SetId(); 
} 
+0

私は単純なプロパティを使いたいと思います。 – user10789

7

IReadOnlyに基づいてICanReadWriteを実装するのではなく、それらを別々にする必要があります。

ie。このように:クラスで同じプロパティが両方のインターフェースをサポートできることを

public class SomeObject : IReadOnly, ICanReadWrite 
{ 
    public string Id 
    { 
     get; 
     set; 
    } 
} 

注:

public interface IReadOnly 
{ 
    string Id 
    { 
     get; 
    } 
} 

public interface ICanReadAndWrite 
{ 
    string Id 
    { 
     get; 
     set; 
    } 
} 

ここではそれらを使用するクラスです。

コメントごとに、堅牢なソリューションを得る唯一の方法は、ラッパーオブジェクトも持つことです。

つまり

、これは良いではありません:呼び出し元と

public class SomeObject : IReadOnly, ICanReadWrite 
{ 
    public string Id 
    { 
     get; 
     set; 
    } 

    public IReadOnly AsReadOnly() 
    { 
     return this; 
    } 
} 

だけでこれを行うことができます:堅牢なソリューションを取得するには

ICanReadWrite rw = obj.AsReadOnly() as ICanReadWrite; 
rw.Id = "123"; 

を、あなたはこのように、ラッパーオブジェクトが必要になります。

public class SomeObject : IReadOnly, ICanReadWrite 
{ 
    public string Id 
    { 
     get; 
     set; 
    } 

    public IReadOnly AsReadOnly() 
    { 
     return new ReadOnly(this); 
    } 
} 

public class ReadOnly : IReadOnly 
{ 
    private IReadOnly _WrappedObject; 

    public ReadOnly(IReadOnly wrappedObject) 
    { 
     _WrappedObject = wrappedObject; 
    } 

    public string Id 
    { 
     get { return _WrappedObject.Id; } 
    } 
} 

これは、呼び出し側がリフレクションを使用するポイントまで機能し、堅牢です。

+1

しかし、ICanReadAndWriteからIReadOnlyにキャストすることはできません。これは、読み取り/書き込みオブジェクトを扱うクラスを持ち、読み取り専用オブジェクトをコンシューマに返すだけの場合に非常に便利です。 – user10789

+0

消費者はちょうどキャストバックすることができます。これは堅牢ではありません。 – recursive

+1

もちろん、それは堅牢ではありませんが、それが機能していれば元の解決策もありませんでした。書き込み可能性を取り除く唯一の方法は、明示的にそれを防ぐラッピングオブジェクトを返すことです。 IReadOnlyだけを実装します。 –

関連する問題