为什么我不能在C#中抽象静态方法?

最近我一直在和供应商合作,我遇到了一个有趣的情况,我想有一个抽象的类,有一个抽象的静态方法。 我在这个主题上阅读了几篇文章,这是有道理的,但是有一个很好的清晰的解释吗?

静态方法没有被实例化 ,它们只是在没有对象引用的情况下可用。

对静态方法的调用是通过类名实现的,而不是通过对象引用完成的,调用它的IL代码将通过定义它的类的名称来调用抽象方法,而不一定是你使用的类的名字。

让我举个例子。

用下面的代码:

public class A { public static void Test() { } } public class B : A { } 

如果你打电话给B.Test,像这样:

 class Program { static void Main(string[] args) { B.Test(); } } 

那么Main方法中的实际代码如下所示:

 .entrypoint .maxstack 8 L0000: nop L0001: call void ConsoleApplication1.A::Test() L0006: nop L0007: ret 

正如你所看到的,这个调用是由A.Test调用的,因为它是定义它的A类,而不是B.Test,尽pipe你可以这样写代码。

如果你有类的类 ,就像在Delphi中一样,你可以创build一个引用types而不是对象的variables,那么你会更多的使用虚拟的,因此抽象的静态方法(也包括构造函数),但是它们是不可用的,因此静态调用在.NET中是非虚拟的。

我意识到,ILdevise人员可以允许编译代码来调用B.Test,并在运行时parsing调用,但它仍然不会是虚拟的,因为您仍然需要在那里编写某种类名称。

虚拟方法和抽象的方法只有在使用一个variables的时候才是有用的,这个variables在运行时可以包含许多不同types的对象,因此你想调用variables中当前对象的正确方法。 使用静态方法,无论如何你都需要通过一个类名,所以调用的确切方法在编译时是已知的,因为它不能也不会改变。

因此,虚拟/抽象静态方法在.NET中不可用。

静态方法不能被inheritance或覆盖,这就是为什么他们不能抽象。 由于静态方法是在类的types而不是实例上定义的,因此必须在该types上显式调用它们。 所以当你想调用一个子类的方法时,你需要用它的名字来调用它。 这使得inheritance无关紧要。

假设您可以暂时inheritance静态方法。 想象一下这个场景:

 public static class Base { public static virtual int GetNumber() { return 5; } } public static class Child1 : Base { public static override int GetNumber() { return 1; } } public static class Child2 : Base { public static override int GetNumber() { return 2; } } 

如果您调用Base.GetNumber(),将调用哪个方法? 哪个值返回? 很容易看到,没有创build对象的实例,inheritance是相当困难的。 没有inheritance的抽象方法只是没有主体的方法,所以不能被调用。

另一位受访者(McDowell)表示,多态只能用于对象实例。 这应该是合格的; 有些语言将类视为“类”或“元类”types的实例。 这些语言支持实例和类(静态)方法的多态性。

C#,就像之前的Java和C ++一样,不是这样一种语言; static关键字明确用于表示该方法是静态绑定而不是dynamic/虚拟。

为了增加前面的解释,静态方法调用在编译时被绑定到一个特定的方法,这相当于排除了多态行为。

这是一个静态字段和方法肯定需要inheritance的情况:

 abstract class Animal { protected static string[] legs; static Animal() { legs=new string[0]; } public static void printLegs() { foreach (string leg in legs) { print(leg); } } } class Human: Animal { static Human() { legs=new string[] {"left leg", "right leg"}; } } class Dog: Animal { static Dog() { legs=new string[] {"left foreleg", "right foreleg", "left hindleg", "right hindleg"}; } } public static void main() { Dog.printLegs(); Human.printLegs(); } //what is the output? //does each subclass get its own copy of the array "legs"? 

我们实际上重写了静态方法(在delphi中),它有点难看,但是对于我们的需求来说,它工作得很好。

我们使用它,所以类可以有一个没有类实例的可用对象的列表,例如,我们有一个如下所示的方法:

 class function AvailableObjects: string; override; begin Result := 'Object1, Object2'; end; 

这是丑陋的,但必要的,这样我们就可以实例化所需的东西,而不是让所有的类只是为了search可用的对象而立即进行实例化。

这是一个简单的例子,但是应用程序本身是一个客户端 – 服务器应用程序,它只有一个服务器提供所有的类,而多个不同的客户端可能不需要服务器拥有的所有东西,永远不需要对象实例。

所以这比维护每个客户端的服务器应用程序要容易得多。

希望这个例子很清楚。

抽象方法是隐式虚拟的。 抽象方法需要一个实例,但静态方法没有实例。 所以,你可以在抽象类中有一个静态方法,它不能是静态抽象(或抽象静态)。

因为C#devise是从Java复制的。 而Java不允许抽象的静态方法。