我一直在与 提供者 最近一段时间,我遇到了一个有趣的情况,我想要一个具有抽象静态方法的抽象类。我读了一些关于这个主题的文章,这有点道理,但是有一个很好的清晰的解释吗?

有帮助吗?

解决方案

静态方法不是 实例化 因此,它们无需对象引用即可使用。

对静态方法的调用是通过类名完成的,而不是通过对象引用,调用它的中间语言(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 进行的,即使您可以这样编写代码。

如果你有 类别类型, ,就像在 Delphi 中一样,您可以创建一个引用类型而不是对象的变量,您将更多地使用虚拟方法,从而抽象静态方法(以及构造函数),但它们不可用,因此静态调用是非-.NET 中的虚拟。

我意识到 IL 设计者可以允许编译代码来调用 B.Test,并在运行时解析该调用,但它仍然不是虚拟的,因为您仍然需要在那里编写某种类名。

虚拟方法(也就是抽象方法)仅在您使用一个变量时才有用,该变量在运行时可以包含许多不同类型的对象,因此您希望为变量中的当前对象调用正确的方法。对于静态方法,无论如何您都需要遍历类名,因此要调用的确切方法在编译时就已知,因为它不能也不会更改。

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

其他提示

静态方法不能被继承或重写,这就是为什么它们不能是抽象的。由于静态方法是在类的类型上定义的,而不是在类的实例上定义的,因此必须在该类型上显式调用它们。所以当你想调用子类上的方法时,你需要使用它的名称来调用它。这使得继承变得无关紧要。

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

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(),会调用哪个方法?返回哪个值?很容易看出,如果不创建对象实例,继承就相当困难。没有继承的抽象方法只是没有主体的方法,因此无法被调用。

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

C# 与之前的 Java 和 C++ 一样,不是这样的语言。这 static 显式使用关键字来表示该方法是静态绑定的而不是动态/虚拟的。

为了补充前面的解释,静态方法调用绑定到特定方法 编译时, ,这就排除了多态行为。

这里有一种情况,静态字段和方法肯定需要继承:

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; 

它很丑陋但很必要,这样我们就可以实例化所需的内容,而不是实例化所有类只是为了搜索可用的对象。

这是一个简单的示例,但应用程序本身是一个客户端-服务器应用程序,它仅在一台服务器中提供所有可用的类,而多个不同的客户端可能不需要服务器拥有的所有内容,也永远不需要对象实例。

因此,这比为每个客户端使用一个不同的服务器应用程序更容易维护。

希望这个例子很清楚。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top