Как я могу обеспечить классу статическое свойство, используя интерфейс или абстракцию? - PullRequest
27 голосов
/ 15 марта 2010

У меня есть один абстрактный класс - скажем, myBase. И я хочу, чтобы все классы, производные от myBase, имели одно статическое поле с именем

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

Итак, каждый дочерний класс может сказать, какие имена параметров он использует; Я хочу статический, потому что я не хочу создавать экземпляр только для этого.

Как мне этого добиться?

Ответы [ 8 ]

26 голосов
/ 15 марта 2010

Вы не можете этого сделать. Интерфейсы, аннотация и т. Д. Не могут применяться к статическим элементам. Если вы хотите выполнить это, вам придется вручную не забывать делать это на всех производных классах.

Кроме того, статические члены наследуются производными классами. Дочерние классы должны скрывать статический родительский член, если они хотят указать альтернативное поведение.

7 голосов
/ 15 марта 2010

В любом случае это не имеет смысла, так как у вас не было бы способа получить доступ к этому статическому свойству без определения типа, тем самым нарушая весь смысл наличия интерфейса.

Я бы просто поместил свойство в интерфейс и направил его статическому члену.

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 голосов
/ 15 марта 2010

Хорошо. Может быть, я не был достаточно ясен. Но в основном я достиг того, что мне нужно, сделав что-то вроде этого:

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

Таким образом, любой класс, производный от этого класса, вызовет исключение, если свойство MyParameterNames будет пытаться достичь имен параметров этого производного класса.

Не идеальный способ, но он помогает мне преодолеть мою проблему.

0 голосов
/ 14 февраля 2019

Все части решения находятся здесь, распределены по нескольким ответам.

  1. Создайте интерфейс, как обычно.
  2. Создайте абстрактный базовый класс, который реализует интерфейс,и определяет любые статические члены, которые будут необходимы.
  3. Наследуйте от абстрактного базового класса, а не интерфейса при создании ваших реальных реализаций.

Хотя это все еще не позволит вамПолучив доступ к Subclass.MyParameterNames из AbstractClass.MyParameterNames, вы сможете убедиться, что это свойство доступно во всех реализациях AbastractClass.

Однако, в зависимости от специфики вашего варианта использования, может быть лучше выставить MyParameterNamesв качестве нестатического члена, и просто реализуйте его как одноэлементный, чтобы для каждого подкласса была только одна копия списка.В любом случае вам все равно нужно будет инициализировать экземпляр класса, чтобы получить нужные данные.

По крайней мере, чтобы получить статические данные, вам нужно знать, что такое специфический подкласс, с которым вы имеете дело, поэтому нет смысла пытаться взглянуть на него через интерфейс, который может быть произвольным, неизвестным типом данных.

0 голосов
/ 07 октября 2018

Хотя невозможно иметь значение 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 голосов
/ 02 мая 2014

Почему бы не сделать make MyParameterNames Virtual и переопределить их в производных классах, чтобы выдать исключение

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

public class DerivedClass : BaseClass
{
    public override List<string> MyParameterNames
    {
        get
        {
            throw new Exception();
        }
    }
}
0 голосов
/ 15 марта 2010

В конструкторе для MyBase можно вызвать GetType() и использовать отражение, чтобы убедиться, что производный класс имеет правильное свойство. Очевидно, что это будет происходить только во время выполнения, но я не совсем уверен, какой смысл будет иметь это ограничение в любом случае: какой вред, если статического свойства нет?

0 голосов
/ 15 марта 2010

Это невозможно. Наследование не может применяться к членам типа (статические члены).

...