如何通过使用接口或抽象来确保类具有静态属性?

时间:2010-03-14 22:44:49

标签: c# interface static abstract-class override

我有一个抽象类-let说myBase。我希望从myBase派生的所有类都有一个名为

的静态字段
public static List<string> MyPArameterNames 
{
get {return _myParameterNames;} 
}

因此,每个子类都可以告诉它使用的参数名称;我想要静态,因为我不想为此创建一个实例。

我怎样才能做到这一点?

8 个答案:

答案 0 :(得分:26)

你做不到。接口,抽象等不能应用于静态成员。如果要完成此任务,则必须手动记住在所有派生类上执行此操作。

此外,静态成员通过派生类继承。如果子类希望指定备用行为,则必须隐藏静态父成员。

答案 1 :(得分:7)

无论如何,它没有任何意义,因为你无法在不确定类型的情况下访问该静态属性,从而打破了无论如何都要设置接口的全部意义。

我只是在接口上放置一个属性,并将其路由到静态成员。

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 :(得分:2)

确定。也许我不够清楚。但是我通过做这样的事情基本上实现了我的需要:

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

因此,如果尝试访问MyParameterNames属性以获取该derived类的参数名称,那么派生自此类的任何类都将抛出异常。

不是一个完美的方式,但它有助于我在某种程度上克服我的问题。

答案 3 :(得分:0)

这是不可能的。继承不能应用于类型的成员(静态成员)。

答案 4 :(得分:0)

您可以在MyBase的构造函数中调用GetType()并使用反射来确保派生类具有正确的属性。显然,这只是在运行时才会发现它,但我不确定这个约束的重点是什么:静态属性不存在会有什么危害呢?

答案 5 :(得分:0)

为什么不make 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();
        }
    }
}

答案 6 :(得分:0)

虽然在接口上不可能有一个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}.");
    }
}

它与具有静态属性并不完全相同(例如,您不能在没有先创建实例的情况下简单地访问该属性),但是在某些用例中它可能会很好地工作。

答案 7 :(得分:0)

解决方案的所有内容都在这里,分布在多个答案中。

  1. 像平常一样创建界面。
  2. 创建一个实现该接口的抽象基类,并定义所需的任何静态成员。
  3. 从抽象基类继承,而不是在创建实际实现时继承于接口。

尽管它仍然不允许您从AbstractClass.MyParameterNames访问Subclass.MyParameterNames,但是您将能够确保AbastractClass的所有实现都具有该属性。

但是,根据用例的具体情况,最好将MyParameterNames公开为非静态成员,并简单地将其实现为单例,以便每个子类只有一个列表副本。无论哪种方式,您都仍然需要初始化该类的实例才能获取所需的数据。

至少,要获取静态数据,您需要知道要处理的 specific 子类,因此尝试查看它没有太大意义。从接口开始,该接口可以是任意的未知数据类型。