题
我最近遇到了一个问题,似乎我需要一个“静态抽象”方法。我知道为什么这是不可能的,但是我该如何解决这个限制呢?
例如,我有一个带有描述字符串的抽象类。由于该字符串对于所有实例都是通用的,因此它被标记为静态,但我想要求从该类派生的所有类都提供自己的 Description 属性,因此我将其标记为抽象:
abstract class AbstractBase
{
...
public static abstract string Description{get;}
...
}
它当然不会编译。我想过使用接口,但接口可能不包含静态方法签名。
我是否应该将其设置为简单的非静态,并始终获取一个实例来获取该类的特定信息?
有任何想法吗?
解决方案
将静态和抽象结合起来有点毫无意义,是的。静态背后的想法是,为了使用有问题的成员,不需要提供类的实例;但是对于abstract,我们期望一个实例是一个提供具体实现的派生类。
我可以理解为什么你想要这种组合,但事实是唯一的结果就是拒绝'this'或任何非静态成员的实现使用。也就是说,父类将规定派生类的实现中的限制,即使在调用抽象或“静态抽象”成员之间没有潜在的区别(因为两者都需要一个具体的实例来确定要使用的实现)
其他提示
你不能。
这样做的地方是属性。
例如
[Name("FooClass")]
class Foo
{
}
如果你不介意推迟实现以合理地实现Description属性,你可以简单地执行
public abstract string ClassDescription {get; }
// ClassDescription is more intention-revealing than Description
实现类会做类似的事情:
static string classDescription="My Description for this class";
override string ClassDescription { get { return classDescription; } }
然后,你的班级必须遵守描述的合同,但你要留给他们理智地做。没有办法以面向对象的方式指定实现(除了通过残忍的,脆弱的黑客攻击)。
但是,在我看来这个描述是类元数据,所以我更喜欢使用其他人描述的属性机制。如果您特别担心多次使用反射,请创建一个反映您所关注的属性的对象,并在Type和Description之间存储字典。这将最小化反射(除了运行时类型检查,这不是那么糟糕)。字典可以存储为通常需要此信息的任何类的成员,或者,如果域中的客户端需要它,则通过单例或上下文对象存储。
如果它是静态的,那么变量只有一个实例,如果我们可以在派生类中使用静态变量完成你想要完成的任务,我看不出继承是否有意义。就个人而言,我认为你会尽量避免实例变种。
为什么不只是经典的方式?
abstract class AbstractBase
{
protected string _Description = "I am boring abstract default value";
}
class Foo : AbstractBase {
public Foo() {
_Description = "I am foo!";
}
}
如果必须在实例上调用它,则不是静态的。
如果你没有在实例上调用它,那么就没有多态性(即就语言而言,ChildA.Description与ChildB.Description完全无关。)
一种可能的解决方法是借助泛型在基类中定义派生类的单例。
import System;
public abstract class AbstractBase<T>
where T : AbstractBase<T>, new()
{
private static T _instance = new T();
public abstract string Description { get; }
public static string GetDescription()
{
return _instance.Description;
}
}
public class DerivedClass : AbstractBase<DerivedClass>
{
public override string Description => "This is the derived Class";
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine(DerivedClass.GetDescription());
Console.ReadKey();
}
}
诀窍是告诉你 AbstractBase<T>
有关如何进行的一些详细信息 DerivedClass
已实施:
- 它是可更新的
where T: new()
所以它可以创建一个 Singleton 实例 - 它源自自身
where T : AbstractBase<T>
所以它知道将会有一个实施Description
这边走 _instance
包含 Description
可以在静态方法中调用的字段 GetDescription()
。这迫使你覆盖 Description
在你的 DerivedClass
并允许您调用它的值 DerivedClass.GetDescription()
你可以使<!> quot; abstract <!>; base方法抛出一个Exception
,那么开发人员就是<!>“警告<!>”;如果他试图在子类上调用此方法而不覆盖。
缺点是可能会扩展类而不使用此方法。然后参考提供的其他答案。