web-dev-qa-db-ja.com

インターフェイスまたは抽象を使用して、クラスに静的プロパティがあることを保証するにはどうすればよいですか?

私には1つの抽象クラスがあります-myBaseとしましょう。そして、myBaseから派生したすべてのクラスに1つの静的フィールドを持たせたい

public static List<string> MyPArameterNames 
{
get {return _myParameterNames;} 
}

したがって、すべての子クラスは、使用するパラメーター名を知ることができます。このためだけにインスタンスを作成したくないので、静的にしたい。

どうすればこれを達成できますか?

28
pencilCake

あなたはそれをすることはできません。インターフェイス、抽象化などは静的メンバーには適用できません。これを達成したい場合は、すべての派生クラスで手動で行うことを忘れないでください。

また、静的メンバーは派生クラスによって継承されます。子クラスは、代替の動作を指定する場合、静的な親メンバーを非表示にする必要があります。

27
Zach Johnson

とにかく、タイプを決定せずにその静的プロパティにアクセスする方法がないため、それは意味がありません。したがって、とにかくインターフェイスを持つという全体的なポイントを壊します。

インターフェイスにプロパティを配置し、静的メンバーにルーティングするだけです。

public interface IMyInterface
{
    void Foo();
    IList<string> Properties { get; }
}

public class ConcreteClass : IMyInterface
{
    public void Foo(){}
    public IList<string> Properties
    {
        get { return s_properties; }
    }
}

しかし、それは私を2番目の質問に導きます-あなたが達成しようとしていることは何ですか?クラスに静的メンバーが必要なのはなぜですか?あなたが本当に望んでいるのは、オブジェクトが与えられたときに、それがどのようなプロパティを持っているかを判断できるようにすることです。では、静的に保存されているのか、インスタンスごとに保存されているのかをコードが気にするのはなぜですか?

契約(何をしたいのか)と実装(サービスのプロバイダーが目標をどのように達成するか)を混同しているようです。

7
kyoryu

OK。多分私は十分に明確ではありませんでした。しかし、私は基本的に次のようなことをすることで必要なことを達成しました:

public abstract myBaseClass
{
 public List<string> MyParameterNames
   {
     get 
         {
             throw 
               new ApplicationException("MyParameterNames in base class 
                                 is not hidden by its child.");
         }
   }
}

したがって、このクラスから派生したクラスは、MyParameterNamesプロパティがその派生クラスのパラメーター名に到達しようとすると、例外をスローします。

完璧な方法ではありませんが、ある意味で問題を克服するのに役立ちます。

2
pencilCake

なぜMyParameterNamesを仮想化し、派生クラスでそれらをオーバーライドして例外をスローしないのですか?

public abstract class BaseClass
{
    public virtual List<string> MyParameterNames
    {
        get;
    }
}

public class DerivedClass : BaseClass
{
    public override List<string> MyParameterNames
    {
        get
        {
            throw new Exception();
        }
    }
}
0
user2882522

それは不可能です。タイプのメンバー(静的メンバー)には継承を適用​​できません。

0
Andrew Bezzub

MyBaseのコンストラクターで、GetType()を呼び出し、リフレクションを使用して、派生クラスに正しいプロパティがあることを確認できます。明らかに、それは実行時にそれを拾うだけですが、とにかくこの制約のポイントが何であるかは本当にわかりません:静的プロパティがない場合の害は何ですか?

0
Dean Harding

ソリューションのすべての部分がここにあり、複数の回答にまたがっています。

  1. 通常どおりにインターフェイスを作成します。
  2. インターフェイスを実装し、必要となる静的メンバーを定義する抽象基本クラスを作成します。
  3. 実際の実装を作成するときは、インターフェイスではなく、抽象基本クラスから継承します。

それでもAbstractClass.MyParameterNamesからSubclass.MyParameterNamesにアクセスすることはできませんが、AbastractClassのすべての実装でそのプロパティを使用できるようにすることができます。

ただし、ユースケースの詳細によっては、MyParameterNamesを非静的メンバーとして公開し、サブクラスごとにリストのコピーが1つだけになるように、シングルトンとして実装する方がよい場合があります。いずれにせよ、必要なデータを取得するには、クラスのインスタンスを初期化する必要があります。

少なくとも、静的データを取得するには、処理している特定のサブクラスを知る必要があるため、インターフェイスからデータを調べようとしても意味がありません。 、これは任意の不明なデータ型にすることができます。

0
Theo Brinkman

インターフェイスにstatic値を設定することはできませんが、抽象クラスに静的な値を設定することは可能です。ただし、このインスタンスは抽象クラスのレベルで保持されます。したがって、すべての派生クラスに共通になります。ニーズに応じて、これを有利に使用できます。つまり、基本クラスにキーが型(派生クラスの型)である辞書を用意し、その下にリストを保持します。

//example of the base class
public abstract class MyAbstractBaseClass
{
    private static readonly IDictionary<Type,IList<MyAbstractBaseClass>> values = new Dictionary<Type,IList<MyAbstractBaseClass>>();
    public List<string> MyParameterNames 
    {
        get
        {
            return values[this.GetType()].Select(x => x.Name).ToList();
        }
    }
    public string Name {get; private set;}
    protected MyAbstractBaseClass(string name)
    {
        //assign the new item's name to the variable
        Name = name;
        //keep a list of all derivations of this class
        var key = this.GetType();
        if (!values.ContainsKey(key))
        {
            values.Add(key, new List<MyAbstractBaseClass>());
        }
        values[key].Add(this);
    }
}

//examples of dervived class implementations
public class MyDerivedClassOne: MyAbstractBaseClass
{
    private MyDerivedClassOne(string name): base(name){}
    public static readonly MyDerivedClassOne Example1 = new MyDerivedClassOne("First Example");
    public static readonly MyDerivedClassOne Example2 = new MyDerivedClassOne("Second Example");
}
public class MyDerivedClassTwo: MyAbstractBaseClass
{
    private MyDerivedClassTwo(string name): base(name){}
    public static readonly MyDerivedClassTwo Example1 = new MyDerivedClassTwo("1st Example");
    public static readonly MyDerivedClassTwo Example2 = new MyDerivedClassTwo("2nd Example");
}

//working example
void Main()
{
    foreach (var s in MyDerivedClassOne.Example1.MyParameterNames)
    {
        Console.WriteLine($"MyDerivedClassOne.Example1.MyParameterNames: {s}.");
    }
    foreach (var s in MyDerivedClassTwo.Example1.MyParameterNames)
    {
        Console.WriteLine($"MyDerivedClassTwo.Example1.MyParameterNames: {s}.");
    }
}

静的プロパティを持つこととまったく同じではありませんが(たとえば、最初にインスタンスを作成せずにプロパティにアクセスすることはできません)、一部のユースケースではうまく機能する可能性があります。

0
JohnLBevan