6

「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として、変更されないある種のプレゼンテーションレイヤーに渡すことができます。(はい、技術的に変更できることはわかっています。これは設計上の問題であり、セキュリティなどではありません)

4

5 に答える 5

19

それは特に悪い考えではありません。実装者は(暗黙的にインターフェイスを実装する場合、単一の読み取り/書き込みプロパティで両方のインターフェイスを満たすことができます)、2つの異なる実装を提供できることに注意してください。

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継承修飾子は、コンパイラにシャットダウンして「そのメンバーを非表示にしている」という警告をスローしないように指示する以外は何もしません。これを省略しても、コンパイルされたコードには影響しません。

于 2009-09-09T12:58:16.307 に答える
7

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

すなわち。このような:

public interface IReadOnly
{
    string Id
    {
        get;
    }
}

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

それらを使用するクラスは次のとおりです。

public class SomeObject : IReadOnly, ICanReadWrite
{
    public 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; }
    }
}

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

于 2009-09-09T13:00:36.153 に答える
1

これは完全に合法であり、ICanReadAndWriteインターフェイスを実装するクラスにとっての意味は、IReadOnlyとして扱われる場合は読み取りのみが可能ですが、ICanReadAndWriteとして扱われる場合は両方を実行できるということです。

于 2009-09-09T12:58:50.527 に答える
0

それがコンパイルされるかどうかはわかりませんが、従うことをお勧めするパターンではありません。IReadOnly明示的なインターフェイスの実装を行う機能を使用すると、理論的には、プロパティのとICanReadAndWriteバージョンに対して2つのまったく異なる実装を提供できIdます。ICanReadAndWriteプロパティを置き換えるのではなく、プロパティのセッターメソッドを追加してインターフェイスを変更することを検討してください。

于 2009-09-09T12:55:54.947 に答える
0

あなたはそれをすることができますが、私はあなたがそれをすることによって何を達成したいのかわかりません。

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

このメソッドはへの参照を返します。これは、を返しIReadOnlyたことは問題ではないことを意味しますICanReadAndWrite。このアプローチの方が良いのではないでしょうか。

public interface IReadOnly
{
    String GetId();
}

public interface ICanReadAndWrite : IReadOnly
{
    String SetId();
}
于 2009-09-09T12:59:18.727 に答える