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

Posted

技术标签:

【中文标题】如何通过使用接口或抽象来确保类具有静态属性?【英文标题】:How can I assure a class to have a static property by using interface or abstract? 【发布时间】:2011-01-27 11:57:20 【问题描述】:

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

的静态字段
public static List<string> MyPArameterNames 

get return _myParameterNames; 

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

我怎样才能做到这一点?

【问题讨论】:

这是不可能的。 很多相关问题:***.com/questions/1266422/…***.com/questions/259026/…***.com/questions/1062468/… 创建类的实例有什么问题? 如果您能描述您尝试使用此功能解决的问题,这可能会有所帮助。我的猜测是,您真正想要的是发现派生类的某些属性,而反射可能是您最好的选择。 【参考方案1】:

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

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

【讨论】:

“手动记住”——天哪,这就像我们没有电脑什么的 那么当我们使用接口声明该类的对象时(如依赖注入的情况),在这种情况下我们将无法使用该静态变量/属性,因为属性不可用在界面中【参考方案2】:

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

【讨论】:

【参考方案3】:

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

【讨论】:

【参考方案4】:

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

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

public interface IMyInterface

    void Foo();
    IList<string> Properties  get; 


public class ConcreteClass : IMyInterface

    public void Foo()
    public IList<string> Properties
    
        get  return s_properties; 
    

但这让我想到了第二个问题——你想要完成什么?为什么你需要在类上有一个静态成员?你真正想要的是,给定一个对象,能够确定它有什么属性,对吧?那么为什么你的代码会关心它们是静态存储还是按实例存储呢?

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

【讨论】:

【参考方案5】:

好的。也许我不够清楚。但我基本上已经通过做这样的事情实现了我所需要的:

public abstract myBaseClass

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

因此,如果 MyParameterNames 属性试图访问该派生类的参数名称,则从此类派生的任何类都将引发异常。

不是一个完美的方法,但它可以帮助我以某种方式克服我的问题。

【讨论】:

你不想要一个静态属性吗? 我说问题标题很好,但你的意思与问题标题无关【参考方案6】:

为什么不将 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'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.");
    

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

【讨论】:

【参考方案8】:

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

    照常创建界面。 创建一个实现接口的抽象基类,并定义所需的所有静态成员。 在创建实际实现时继承抽象基类,而不是接口。

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

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

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

【讨论】:

以上是关于如何通过使用接口或抽象来确保类具有静态属性?的主要内容,如果未能解决你的问题,请参考以下文章

PHP 抽象类,接口,抽象方法,静态方法

接口接口优点接口的属性和方法特性接口与继承的区别接口与抽象类的区别匿名实现类JDK1.8新特性打印类名称

对象和类

PHP pdo 实例作为私有静态属性

关于如何在Python中使用静态类或抽象方法的权威指南

如何覆盖父对象的静态属性并让父对象访问 PHP 中的新值?