42

我最近遇到了一个问题,我似乎需要一个“静态抽象”方法。我知道为什么这是不可能的,但我该如何解决这个限制?

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

abstract class AbstractBase
{
    ...
    public static abstract string Description{get;}
    ...
}

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

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

有任何想法吗?

4

8 回答 8

33

你不能。

这样做的地方是属性。

例如

[Name("FooClass")]
class Foo
{
}
于 2009-05-05T07:02:10.220 回答
7

如果您不介意推迟实现以明智地实现 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; } }

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

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

于 2009-05-11T18:20:46.527 回答
6

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

我明白你为什么想要这种组合,但事实是唯一的效果是拒绝实现使用“this”或任何非静态成员。也就是说,父类将在派生类的实现中规定一个限制,即使调用抽象或“静态抽象”成员之间没有根本区别(因为两者都需要一个具体实例来确定要使用的实现)

于 2009-05-05T07:03:47.830 回答
6

如果它是静态的,那么只有一个变量实例,如果我们可以在派生类中使用静态变量完成您想要完成的事情,我看不出继承会有什么意义。就我个人而言,我认为你会尽量避免使用实例变量。

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

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

class Foo : AbstractBase {

     public Foo() {
       _Description = "I am foo!";
     }
}
于 2009-05-05T07:16:28.377 回答
4

一种可能的解决方法是在泛型的帮助下在基类中定义派生类的单例。

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可以在静态 Method 中调用的字段GetDescription()。这会迫使您覆盖Description您的DerivedClass并允许您使用DerivedClass.GetDescription()

于 2018-06-10T18:22:52.787 回答
3

如果必须在实例上调用它,则它不是静态的。

如果您没有在实例上调用它,那么就没有多态性在起作用(即就语言而言,ChildA.Description 与 ChildB.Description 完全无关)。

于 2009-05-05T07:03:00.420 回答
2

你可以...

在抽象类...

 protected abstract InWindow WindowInstance { get; set; }

在派生类中...

    private static InWindow _instance;


    protected override InWindow WindowInstance
    {
        get => _instance;
        set => _instance = value;
    }
于 2021-04-14T11:47:37.757 回答
0

您可以使“抽象”基方法抛出一个Exception,因此如果开发人员尝试在子类上调用此方法而不覆盖,则会被“警告”。

缺点是可能会扩展类而不使用此方法。然后参考提供的其他答案。

于 2014-04-09T19:32:20.203 回答