Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

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

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

Почему бы не сделать 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();
        }
    }
}

Ответ 7

Хотя 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 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}.");
    }
}

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

Ответ 8

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

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

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

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

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