C#,像方法一样实现'静态抽象'

Cal*_*ius 41 c# static abstract

我最近遇到了一个问题,似乎我需要一个'静态抽象'方法.我知道为什么这是不可能的,但我怎样才能解决这个限制?

例如,我有一个抽象类,它有一个描述字符串.由于此字符串对于所有实例都是通用的,因此它被标记为static,但我想要求从此类派生的所有类都提供它们自己的Description属性,因此我将其标记为abstract:

abstract class AbstractBase
{
    ...
    public static abstract string Description{get;}
    ...
}
Run Code Online (Sandbox Code Playgroud)

它当然不会编译.我想过使用接口但接口可能不包含静态方法签名.

我应该简单地使它成为非静态的,并且总是得到一个实例来获取特定于类的信息吗?

有任何想法吗?

lep*_*pie 31

你不能.

这样做的地方是属性.

例如

[Name("FooClass")]
class Foo
{
}
Run Code Online (Sandbox Code Playgroud)

  • 确实......可以使用public static Description属性来获取属性值,以使其更易于访问... (3认同)
  • 不会反映那么贵吗? (3认同)

Jas*_*rue 6

如果您不介意推迟实现以合理地实现Description属性,那么您可以这样做

public abstract string ClassDescription {get; } 
// ClassDescription is more intention-revealing than Description
Run Code Online (Sandbox Code Playgroud)

实现类将执行以下操作:

static string classDescription="My Description for this class";
override string  ClassDescription { get { return classDescription; } }
Run Code Online (Sandbox Code Playgroud)

然后,你的班级必须遵守描述的合同,但你留给他们理智地做.没有办法以面向对象的方式指定实现(除了通过残忍的,脆弱的黑客攻击).

但是,在我看来这个描述是类元数据,所以我更喜欢使用其他人描述的属性机制.如果您特别担心多次使用反射,请创建一个反映您所关注的属性的对象,并在"类型"和"描述"之间存储字典.这将最小化反射(除了运行时类型检查,这不是那么糟糕).字典可以存储为通常需要此信息的任何类的成员,或者,如果域中的客户端需要它,则通过单例或上下文对象存储.


bdo*_*lan 5

将静态和抽象结合起来有点毫无意义,是的.静态背后的想法是,为了使用有问题的成员,不需要提供类的实例; 但是对于abstract,我们期望一个实例是一个提供具体实现的派生类.

我可以看到为什么你想要这种组合,但事实是唯一的影响是拒绝实现使用'this'或任何非静态成员.也就是说,父类将规定派生类的实现中的限制,即使在调用抽象或"静态抽象"成员之间没有潜在的区别(因为两者都需要一个具体的实例来确定要使用的实现)

  • 这不是没有意义的.想象一下,你正在设计一个框架.您需要实现ISomething的类公开一些编译时已知数据.例如,"友好的班级名称".您希望编译器确保所有ISomethings都具有此属性.如果您现在想要这样做,那么您必须使用实例属性.这意味着创建一个实例,而不仅仅是查询类型.太糟糕了. (87认同)
  • 我同意@RyanBarrett,对于框架设计,强制消费者在派生类中提供函数可能很有用,但也可以通过合同声明该函数是静态执行的,而不存在实例. (5认同)
  • 另一种方法是允许抽象基类声明它必须在每个子节点上定义某个属性(同样用于提供编译时常量数据) (2认同)

Cha*_*ant 5

如果它是静态的,那么变量只有一个实例,如果我们能够在派生类中使用静态变量完成你想要完成的任务,我不会看到继承是如何有意义的.我个人认为你会尽量避免实例var.

为什么不只是经典的方式?

abstract class AbstractBase
{
    protected string _Description = "I am boring abstract default value";
}

class Foo : AbstractBase {

     public Foo() {
       _Description = "I am foo!";
     }
}
Run Code Online (Sandbox Code Playgroud)