开发者

How can I assure a class to have a static property by using interface or abstract?

I have one abstract class -let's say myBase. And I want all the classes derived from myBase to have one static field called

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

So, every child class can tell what parameter names it uses; I want static because I do not want to create an instance just for this.

Ho开发者_开发问答w can I achieve this?


You can't do that. Interfaces, abstract, etc. cannot apply to static members. If you want to accomplish this, you will have to manually remember to do it on all deriving classes.

Also, static members are inherited by deriving classes. Child classes must hide the static parent member if they wish to specify alternate behavior.


It doesn't make sense, anyway, as you'd have no way to access that static property without determining the type, thus breaking the whole point of having an interface anyway.

I'd just put a property on the interface, and route it to the static member.

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

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

But that leads me to the second question - what is it that you are trying to accomplish? Why do you need to have a static member on the class? What you really want is, given an object, to be able to determine what properties it has, right? So why would your code care if they're stored statically or per instance?

It seems like you're confusing contract (what you want to be able to do) with implementation (how the provider of the service accomplishes the goal).


Ok. Maybe I was not clear enough. But I have achieved basically what I need by doing something like this:

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

So any class derived from this class, will throw an exception if MyParameterNames property is tried to reach the parameter names of that derivedclass.

Not a perfect way, but it helps me to overcome my problem in a way.


It is imposible. Inheritance cannot be aplied to the members of the type (static members).


All the pieces of the solution are here, spread across multiple answers.

  1. Create the interface as you would normally.
  2. Create an abstract base class which implements the interface, and defines any static members which will be required.
  3. Inherit from the abstract base class, rather than the interface when creating your actual implementations.

While it still will not allow you to access Subclass.MyParameterNames from AbstractClass.MyParameterNames, you will be able to ensure that all implementations of AbastractClass have that property available.

Depending on the specifics of your use case, however, it may be better to expose MyParameterNames it as a non-static member, and simply implement it as a singleton so that there is only one copy of the list for each subclass. Either way, you'll still need to initialize an instance of the class in order to get the data you want.

At the very least, to get the static data, you'll need to know what specific subclass you're dealing with, so it doesn't make much sense to attempt to look at it from an interface, which can be an arbitrary, unknown data type.


You can, in the constructor for MyBase, call GetType() and use reflection to ensure the derived class has the correct property. Obviously, that's only going to pick it up at runtime, but I'm not really sure what the point of this constraint would be anyway: what's the harm if the static property isn't there?


Why not make the make MyParameterNames Virtual and override them in the derived classes to throw the exception

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

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


Whilst it's not possible to have a static value on an interface, it is possible to have a static value on an abstract class. This instance is held at the abstract class's level though; so will be common to all derived classes. Depending on your needs you can use this to your advantage; i.e. have a dictionary on your base class the key for which is a type (the type being that of the derived class), then hold your lists under that.

//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}.");
    }
}

It's not exactly the same as having a static property (e.g. you cannot simply access the property without first creating an instance), but it may work well for some use cases.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜