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

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

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

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

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


person pencilCake    schedule 14.03.2010    source источник
comment
Это невозможно.   -  person SLaks    schedule 15.03.2010
comment
Многие связанные вопросы: stackoverflow.com/questions/1266422/ stackoverflow.com/questions/259026/ stackoverflow.com/questions/1062468 /   -  person Ben S    schedule 15.03.2010
comment
Что не так с созданием экземпляров классов?   -  person Juliet    schedule 15.03.2010
comment
Было бы полезно, если бы вы описали проблему, которую пытаетесь решить с помощью этой функции. Я предполагаю, что на самом деле вам нужно обнаружить определенные атрибуты производных классов, и отражение, вероятно, лучший выбор для этого.   -  person Daniel Pryden    schedule 15.03.2010


Ответы (8)


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

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

person Zach Johnson    schedule 14.03.2010
comment
вручную запомните - ну, как будто у нас нет компьютеров или чего-то подобного - person tofutim; 10.12.2013
comment
И как насчет того, когда мы используем интерфейс для объявления объекта этого класса (как в случае внедрения зависимости), в этом случае мы не сможем использовать эту статическую переменную / свойство, потому что свойство недоступно в интерфейсе - person Adeem; 19.08.2016

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

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

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

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

Но это подводит меня ко второму вопросу - чего вы пытаетесь достичь? Зачем вам нужен статический член в классе? Что вам действительно нужно, так это дать объекту возможность определить, какими свойствами он обладает, верно? Так зачем вашему коду заботиться о том, хранятся ли они статически или для каждого экземпляра?

Похоже, вы путаете контракт (то, что вы хотите делать) с реализацией (как поставщик службы достигает цели).

person kyoryu    schedule 14.03.2010
comment
публичное ключевое слово в интерфейсе, rly? - person sasjaq; 20.02.2014
comment
@sasjaq - Странно, что вы сделали такой комментарий, когда через четыре года после того, как был дан ответ, вы оказались на этом вопросе ... Что я могу только предположить, это потому, что вы не знали ответа на этот вопрос, который ответ доставляет. - person Jack_Hu; 03.05.2019
comment
@Jack_Hu Странно, что вы сделали такой комментарий, когда еще через пять лет после того, как комментарий был дан ...;) - person sasjaq; 03.05.2019
comment
@Jack_Hu Просто чтобы добавить к некроу этого раздела комментариев ... @ sasjaq был правильным, чтобы указать на это. Метод интерфейса или свойство с модификатором public не компилируются. - person Lews Therin; 07.05.2019

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

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

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

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

person pencilCake    schedule 14.03.2010
comment
Разве вам не нужно статическое свойство? - person SvendK; 12.02.2016
comment
Я говорю, что заголовок вопроса хороший, но то, что вы имели в виду, не связано с заголовком вопроса - person mkb; 29.03.2016

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

person Andrew Bezzub    schedule 14.03.2010

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

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

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

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

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

person Theo Brinkman    schedule 13.02.2019

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

person Dean Harding    schedule 14.03.2010

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

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

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

Хотя в интерфейсе невозможно иметь значение 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}.");
    }
}

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

person JohnLBevan    schedule 07.10.2018