.net-为什么我不能在C#中使用抽象静态方法?

Translate

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

This question and all comments follow the "Attribution Required."

所有的回答

Translate

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

静态方法的调用是通过类名完成的,而不是通过对象引用完成的,调用该方法的中间语言(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中的-virtual。

我意识到IL设计器可以允许编译代码以调用B.Test,并在运行时解决该调用,但是它仍然不是虚拟的,因为您仍然必须在其中编写某种类名。

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

因此,.NET中不提供虚拟/抽象静态方法。

来源
Translate

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

假设您可以暂时继承静态方法。想象一下这种情况:

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

来源
Translate

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

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

来源
Translate

为了增加前面的解释,静态方法调用被绑定到特定的方法上编译时间,而排除多态行为。

来源
Translate

在这种情况下,绝对需要继承静态字段和方法:

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"?
来源
Translate

我们实际上重写了静态方法(在delphi中),这有点丑陋,但它可以很好地满足我们的需求。

我们使用它,以便类可以在没有类实例的情况下获得其可用对象的列表,例如,我们有一个如下所示的方法:

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

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

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

因此,与为每个客户端使用一个不同的服务器应用程序相比,维护起来容易得多。

希望这个例子很清楚。

来源
Translate

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

来源