web-dev-qa-db-ja.com

C#:インターフェイス継承ゲッター/セッター

特定の可変オブジェクトと密接に関連して使用される一連のインターフェースがあります。

オブジェクトの多くのユーザーは、オブジェクトから値を読み取る機能のみを必要とし、次にいくつかのプロパティのみを必要とします。名前空間の汚染(より簡単なインテリセンス)を回避し、使用目的を理解するために、読み取り専用の方法でいくつかの「キー」プロパティのみを公開する小さなベースインターフェイスが必要です。

ただし、ほとんどすべての実装は、変更可能性を含む完全なインターフェイスをサポートします。

残念ながら、C#でその概念を表現する障害に遭遇しました。

interface IBasicProps {
   public int Priority { get; }
   public string Name {get;}
   //... whatever
}

interface IBasicPropsWriteable:IBasicProps  {
   public int Priority { set; } //warning CS0108: [...] hides inherited member [...]
   public string Name { set; }
   //... whatever
}

私は確かにメンバーを隠すつもりはなかったので、それは良くありません!

もちろん、メソッドを使用してこれをうまく解決することはできますが、rightの選択は何ですか?インターフェイスを分割しても意図を伝える以外の目的がない場合でも、「コア」インターフェイスをできるだけ小さくしたいと思います。分割インターフェースを使用すると、どのメソッドが更新を行わないかが非常に明確になり、コードの記述が少し明確になります(言うまでもなく、かなりの数の単純なケースに十分な、Nice-n-simple静的シングルトンスタブも可能です) 。

抽象クラスなどは避けたいです。それらは、再実装または迅速な単一目的のシムを、より複雑で手に負えないものにします。

それで、アイデア?

29
Eamon Nerbonne

インターフェイスに隠れているメソッドは、それほど汚れていません。私は次のようなもので行きます:

interface IBasicProps {
   int Priority { get; }
   string Name {get;}
   //... whatever
}

interface IBasicPropsWriteable:IBasicProps  {
   new int Priority { get; set; }
   new string Name { get; set; }
   //... whatever
}
class Foo : IBasicPropsWriteable {
    public int Priority {get;set;}
    public string Name {get;set;}
/* optional
    int IBasicProps.Priority {get {return Priority;}}
    string IBasicProps.Name {get {return Name;}}
*/
}
28
Marc Gravell

読み取りと書き込みが許可されている場合に明確にすることが目標である場合は、プロパティではなく、別々のgetterメソッドとsetterメソッドを使用します。

interface IBasicProps {
   int GetPriority();
   string GetName();
   //... whatever
}

interface IBasicPropsWriteable:IBasicProps  {
   void SetPriority(int priority);
   void SetName(string name);
   //... whatever
}
4

1つの方法は、単にインターフェースの継承をスキップすることです。 1つの読み取り専用インターフェースと1つの書き込み専用を作成し、必要に応じて実装します。

interface IBasicPropsReadable {
   int Priority { get; }
   string Name { get; }
}

interface IBasicPropsWriteable  {
   int Priority { set; }
   string Name { set; }
}

class SomeClassReadWrite : IBasicPropsReadable, IBasicPropsWriteable {
    int Priority { get; set; }
    string Name { get; set; }
}

class SomeClassReadOnly : IBasicPropsReadable {
    int Priority { get; }
    string Name { get; }
}
2
Fredrik Mörk

インターフェイスを無関係のままにして、クラスに両方のインターフェイスを実装させることができます。結局のところ、すべてのインターフェースは単にコントラクトを定義しているだけであり、コントラクトを関連付ける必要はありません。書き込み可能なインターフェイスを他のインターフェイスから派生させるようにコーディングする場合は、最適化にすぎないように思われるため、1つのインターフェイスを指定するだけで済みます。

public interface IBasicProps
{
   int Priority { get; }
   string Name {get;}
   //... whatever
}

public interface IBasicPropsWriteable
{
   int Priority { get; set; }
   string Name { get; set; }
   //... whatever
}

public class Foo : IBasicProps, IBasicPropsWriteable
{
   public int Priority { get; set; }
   public string Name { get; set; }

   // whatever
}

本当に最適化が必要な場合は、両方から派生する別のインターフェースを作成し、クラスにそれを実装させることができます。

public interface IBasicPropsAll : IBasicProps, IBasicPropsWriteable  { }

public class Foo : IBasicPropsAll
{
   public int Priority { get; set; }
   public string Name { get; set; }

   // whatever
}
1
tvanfosson