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

发布于 2024-08-25 15:43:02 字数 243 浏览 4 评论 0原文

我有一个抽象类 - 比方说 myBase。我希望从 myBase 派生的所有类都有一个名为的静态字段,

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

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

我怎样才能实现这个目标?

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.

How can I achieve this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

回梦 2024-09-01 15:43:02

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

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

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.

伊面 2024-09-01 15:43:02

从 C# 11 开始,您可以按照您的预期进行操作:

public class StaticInterfaceImplementorClass : IStaticInterface
{
    public static int MyStaticProperty { get; set; } = 0;
}

interface IStaticInterface
{
    public static abstract int MyStaticProperty { get; set; }
}

请注意,如果您想强制派生类来实现属性,则必须声明属性 abstract。如果您没有将其定义为abstract,则必须提供默认实现。在这种情况下,派生类可以忽略该属性,因为默认实现将始终存在。

As of C# 11 you can do it as you would probably expect:

public class StaticInterfaceImplementorClass : IStaticInterface
{
    public static int MyStaticProperty { get; set; } = 0;
}

interface IStaticInterface
{
    public static abstract int MyStaticProperty { get; set; }
}

Note that you must declare your property abstract if you want to enforce deriving classes to implement it. If you don't define it as abstract, you must provide a default implementation. In this case, derived classes can ignore the property as the default implementation will always be there.

堇年纸鸢 2024-09-01 15:43:02

无论如何,这没有意义,因为如果不确定类型,您就无法访问该静态属性,从而破坏了接口的全部意义。

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

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

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

但这引出了第二个问题——你想要实现什么目标?为什么类中需要有一个静态成员?您真正想要的是,给定一个对象,能够确定它具有哪些属性,对吧?那么,为什么您的代码会关心它们是静态存储还是按实例存储呢?

看来您将合同(您希望能够做什么)与实施(服务提供商如何实现目标)混淆了。

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).

我最亲爱的 2024-09-01 15:43:02

好的。也许是我表达得不够清楚。但我通过执行以下操作基本上已经实现了我所需要的:

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

因此,如果尝试 MyParameterNames 属性访问该派生类的参数名称,则从此类派生的任何类都会抛出异常。

这不是一个完美的方法,但它在某种程度上帮助我克服了我的问题。

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.

场罚期间 2024-09-01 15:43:02

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

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

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

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

至少,要获取静态数据,您需要知道您正在处理的特定子类,因此尝试从接口查看它没有多大意义,它可以是任意的、未知的数据类型。

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.

东北女汉子 2024-09-01 15:43:02

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

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

凉栀 2024-09-01 15:43:02

虽然接口上不可能有静态值,但抽象类上可以有静态值。不过,这个实例是在抽象类的级别上保存的;所以对于所有派生类来说都是通用的。根据您的需要,您可以利用它来发挥自己的优势;即在您的基类上有一个字典,其键是一个类型(该类型是派生类的类型),然后将您的列表保存在该字典下。

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

它与静态属性并不完全相同(例如,您不能在不先创建实例的情况下简单地访问该属性),但它可能适用于某些用例。

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.

满意归宿 2024-09-01 15:43:02

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

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?

世界等同你 2024-09-01 15:43:02

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

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();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文