可以在C#中覆盖静态方法吗?

asp*_*ing 34 c# static-methods overriding final

我被告知static方法是隐含的final,因此不能被覆盖.真的吗?

  1. 有人可以提供一个更好的覆盖静态方法的例子吗?

  2. 如果静态方法只是类方法,那么拥有它们的真正用途是什么?

atl*_*ste 32

(1)静态方法不能被覆盖,但可以使用"new"关键字隐藏它们.大多数重写方法意味着您引用基类型并希望调用派生方法.因为静态是类型的一部分,并且不受vtable查找的影响,这些查找没有意义.

例如静力不能做:

public class Foo { 
    public virtual void Bar() { ... }
}
public class Bar : Foo {
    public override void Bar() { ... }
}

// use:
Foo foo = new Bar(); // make an instance
foo.Bar(); // calls Bar::Bar
Run Code Online (Sandbox Code Playgroud)

由于静态不适用于实例,因此请始终明确指定Foo.Bar或Bar.Bar.所以覆盖在这里没有意义(尝试在代码中表达它......).

(2)静态方法有不同的用法.例如,它在Singleton模式中用于获取类型的单个实例.另一个例子是'static void Main',它是程序中的主要访问点.

基本上,只要您不想要或在使用它之前无法创建对象实例,就可以使用它们.例如,当静态方法创建对象时.

[更新]

一个简单的隐藏示例:

public class StaticTest
{
    public static void Foo() { Console.WriteLine("Foo 1"); }
    public static void Bar() { Console.WriteLine("Bar 1"); }
}

public class StaticTest2 : StaticTest
{
    public new static void Foo() { Console.WriteLine("Foo 2"); }
    public static void Some() { Foo(); Bar(); } // Will print Foo 2, Bar 1
}

public class TestStatic
{
    static void Main(string[] args)
    {
        StaticTest2.Foo();
        StaticTest2.Some();
        StaticTest.Foo();
        Console.ReadLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,如果您创建了类static,则无法执行此操作.静态类必须派生自object.

这与继承之间的主要区别在于编译器可以在编译时确定在使用静态时要调用哪个方法.如果您有对象实例,则需要在运行时执行此操作(称为vtable查找).

  • 什么时候这个Foo < - > Bar废话结束??? 停止使用FoorBar作为示例,在每种情况下,Bar和Foo是类或子类或函数或方法.所以最重要的是什么?只需使用Animals进行子类化和覆盖操作.10倍 (4认同)

Yaa*_*lis 5

您不会覆盖静态方法.你隐藏它.有关详细信息,请参阅此答案.

使用静态方法的一些原因:

  1. 它们比实例方法一点.另请参阅这篇msdn文章,它提供了性能数据来支持这一点(内联静态调用平均0.2 ns,静态调用avg 6.1ns,内联实例调用avg 1.1 ns,实例调用avg 6.8 ns)
  2. 写出更简洁 - 不需要实例化一个类来获取它们(并且实例化也会影响性能)

  • 所有*方法*仅"创建"一次.甚至非静态方法也只有一个代码副本(IL代码在编译时创建并在运行时转换为机器代码*一次*).不要混淆代码和数据!非静态方法只能通过对象的实例进行*调用*,但这是因为传递给它的隐藏的"this"指针.代码本身是"静态的",因为它是固定的和单独的. (2认同)

Nee*_*eel 5

那么你不能覆盖静态方法.静态方法不能是虚拟的,因为它与类的实例无关.

派生类中的"重写"方法实际上是一种新方法,与基类中定义的方法无关(因此是新关键字).

这是一个重要的事情要理解:当类型继承自其他类型时,它们实现了一个公共契约,而静态类型不受任何契约的约束(从纯OOP的角度来看).语言中没有技术方法可以将两个静态类型与"继承"契约联系起来.如果你在两个不同的地方"覆盖"Log方法.

如果你考虑重写静态方法,它就没有意义; 为了进行虚拟调度,您需要一个要检查的对象的实际实例.

静态方法也无法实现接口; 如果这个类正在实现一个IRolesService接口,那么我认为该方法根本不应该是静态的.有一个实例方法更好的设计,所以当你准备好时你可​​以用真实的服务换掉你的MockRoleService