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

时间:2022-09-02 12:01:48

I've been working with providers a fair bit lately, and I came across an interesting situation where I wanted to have an abstract class that had an abstract static method. I read a few posts on the topic, and it sort of made sense, but is there a nice clear explanation?

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

7 个解决方案

#1


146  

Static methods are not instantiated as such, they're just available without an object reference.

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

A call to a static method is done through the class name, not through an object reference, and the IL code to call it will call the abstract method through the name of the class that defined it, not necessarily the name of the class you used.

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

Let me show an example.

我举个例子。

With the following code:

用下面的代码:

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

public class B : A
{
}

If you call B.Test, like this:

如果你调用B。测试是这样的:

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

Then the actual code inside the Main method is as follows:

那么主方法内部的实际代码如下:

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

As you can see, the call is made to A.Test, because it was the A class that defined it, and not to B.Test, even though you can write the code that way.

正如您所看到的,调用是对A进行的。测试,因为定义它的是A类,而不是B类。测试,即使您可以这样编写代码。

If you had class types, like in Delphi, where you can make a variable referring to a type and not an object, you would have more use for virtual and thus abstract static methods (and also constructors), but they aren't available and thus static calls are non-virtual in .NET.

如果您有类类型,比如在Delphi中,您可以创建一个变量来引用类型而不是对象,那么您将对虚拟的和抽象的静态方法(以及构造函数)有更多的使用,但是它们不可用,因此在. net中静态调用是非虚拟的。

I realize that the IL designers could allow the code to be compiled to call B.Test, and resolve the call at runtime, but it still wouldn't be virtual, as you would still have to write some kind of class name there.

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

Virtual methods, and thus abstract ones, are only useful when you're using a variable which, at runtime, can contain many different types of objects, and you thus want to call the right method for the current object you have in the variable. With static methods you need to go through a class name anyway, so the exact method to call is known at compile time because it can't and won't change.

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

Thus, virtual/abstract static methods are not available in .NET.

因此,在。net中不能使用虚拟/抽象静态方法。

#2


42  

Static methods cannot be inherited or overridden, and that is why they can't be abstract. Since static methods are defined on the type, not the instance, of a class, they must be called explicitly on that type. So when you want to call a method on a child class, you need to use its name to call it. This makes inheritance irrelevant.

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

Assume you could, for a moment, inherit static methods. Imagine this scenario:

假设您可以暂时继承静态方法。设想一下这样的情景:

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; }
}

If you call Base.GetNumber(), which method would be called? Which value returned? Its pretty easy to see that without creating instances of objects, inheritance is rather hard. Abstract methods without inheritance are just methods that don't have a body, so can't be called.

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

#3


15  

Another respondent (McDowell) said that polymorphism only works for object instances. That should be qualified; there are languages that do treat classes as instances of a "Class" or "Metaclass" type. These languages do support polymorphism for both instance and class (static) methods.

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

C#, like Java and C++ before it, is not such a language; the static keyword is used explicitly to denote that the method is statically-bound rather than dynamic/virtual.

c#,就像Java和c++之前一样,不是一种语言;静态关键字用于显式地表示方法是静态绑定的,而不是动态/虚拟的。

#4


8  

To add to the previous explanations, static method calls are bound to a specific method at compile-time, which rather rules out polymorphic behavior.

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

#5


8  

Here is a situation where there is definitely a need for inheritance for static fields and methods:

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

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"?

#6


4  

We actually override static methods (in delphi), it's a bit ugly, but it works just fine for our needs.

我们实际上重写了静态方法(在delphi中),这有点难看,但是它很适合我们的需要。

We use it so the classes can have a list of their available objects without the class instance, for example, we have a method that looks like this:

我们使用它,这样类就可以在没有类实例的情况下拥有它们的可用对象列表,例如,我们有一个方法看起来像这样:

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

It's ugly but necessary, this way we can instantiate just what is needed, instead of having all the classes instantianted just to search for the available objects.

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

This was a simple example, but the application itself is a client-server application which has all the classes available in just one server, and multiple different clients which might not need everything the server has and will never need an object instance.

这是一个简单的示例,但应用程序本身是一个客户机-服务器应用程序,它在一个服务器中拥有所有可用的类,以及多个不同的客户机,这些客户机可能不需要服务器拥有的所有东西,也永远不需要对象实例。

So this is much easier to maintain than having one different server application for each client.

因此,这比为每个客户机应用一个不同的服务器应用程序要容易得多。

Hope the example was clear.

希望这个例子是清楚的。

#7


0  

The abstract methods are implicitly virtual. Abstract methods require an instance, but static methods do not have an instance. So, you can have a static method in an abstract class, it just cannot be static abstract (or abstract static).

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

#1


146  

Static methods are not instantiated as such, they're just available without an object reference.

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

A call to a static method is done through the class name, not through an object reference, and the IL code to call it will call the abstract method through the name of the class that defined it, not necessarily the name of the class you used.

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

Let me show an example.

我举个例子。

With the following code:

用下面的代码:

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

public class B : A
{
}

If you call B.Test, like this:

如果你调用B。测试是这样的:

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

Then the actual code inside the Main method is as follows:

那么主方法内部的实际代码如下:

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

As you can see, the call is made to A.Test, because it was the A class that defined it, and not to B.Test, even though you can write the code that way.

正如您所看到的,调用是对A进行的。测试,因为定义它的是A类,而不是B类。测试,即使您可以这样编写代码。

If you had class types, like in Delphi, where you can make a variable referring to a type and not an object, you would have more use for virtual and thus abstract static methods (and also constructors), but they aren't available and thus static calls are non-virtual in .NET.

如果您有类类型,比如在Delphi中,您可以创建一个变量来引用类型而不是对象,那么您将对虚拟的和抽象的静态方法(以及构造函数)有更多的使用,但是它们不可用,因此在. net中静态调用是非虚拟的。

I realize that the IL designers could allow the code to be compiled to call B.Test, and resolve the call at runtime, but it still wouldn't be virtual, as you would still have to write some kind of class name there.

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

Virtual methods, and thus abstract ones, are only useful when you're using a variable which, at runtime, can contain many different types of objects, and you thus want to call the right method for the current object you have in the variable. With static methods you need to go through a class name anyway, so the exact method to call is known at compile time because it can't and won't change.

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

Thus, virtual/abstract static methods are not available in .NET.

因此,在。net中不能使用虚拟/抽象静态方法。

#2


42  

Static methods cannot be inherited or overridden, and that is why they can't be abstract. Since static methods are defined on the type, not the instance, of a class, they must be called explicitly on that type. So when you want to call a method on a child class, you need to use its name to call it. This makes inheritance irrelevant.

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

Assume you could, for a moment, inherit static methods. Imagine this scenario:

假设您可以暂时继承静态方法。设想一下这样的情景:

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; }
}

If you call Base.GetNumber(), which method would be called? Which value returned? Its pretty easy to see that without creating instances of objects, inheritance is rather hard. Abstract methods without inheritance are just methods that don't have a body, so can't be called.

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

#3


15  

Another respondent (McDowell) said that polymorphism only works for object instances. That should be qualified; there are languages that do treat classes as instances of a "Class" or "Metaclass" type. These languages do support polymorphism for both instance and class (static) methods.

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

C#, like Java and C++ before it, is not such a language; the static keyword is used explicitly to denote that the method is statically-bound rather than dynamic/virtual.

c#,就像Java和c++之前一样,不是一种语言;静态关键字用于显式地表示方法是静态绑定的,而不是动态/虚拟的。

#4


8  

To add to the previous explanations, static method calls are bound to a specific method at compile-time, which rather rules out polymorphic behavior.

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

#5


8  

Here is a situation where there is definitely a need for inheritance for static fields and methods:

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

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"?

#6


4  

We actually override static methods (in delphi), it's a bit ugly, but it works just fine for our needs.

我们实际上重写了静态方法(在delphi中),这有点难看,但是它很适合我们的需要。

We use it so the classes can have a list of their available objects without the class instance, for example, we have a method that looks like this:

我们使用它,这样类就可以在没有类实例的情况下拥有它们的可用对象列表,例如,我们有一个方法看起来像这样:

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

It's ugly but necessary, this way we can instantiate just what is needed, instead of having all the classes instantianted just to search for the available objects.

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

This was a simple example, but the application itself is a client-server application which has all the classes available in just one server, and multiple different clients which might not need everything the server has and will never need an object instance.

这是一个简单的示例,但应用程序本身是一个客户机-服务器应用程序,它在一个服务器中拥有所有可用的类,以及多个不同的客户机,这些客户机可能不需要服务器拥有的所有东西,也永远不需要对象实例。

So this is much easier to maintain than having one different server application for each client.

因此,这比为每个客户机应用一个不同的服务器应用程序要容易得多。

Hope the example was clear.

希望这个例子是清楚的。

#7


0  

The abstract methods are implicitly virtual. Abstract methods require an instance, but static methods do not have an instance. So, you can have a static method in an abstract class, it just cannot be static abstract (or abstract static).

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