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

时间:2013-02-12 08:21:10

标签: c# override static-methods final

我被告知static方法隐含final,因此无法覆盖。真的吗?

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

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

3 个答案:

答案 0 :(得分:29)

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

E.g。静力学无法做到:

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

由于静态不适用于实例,因此请始终明确指定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();
    }
}

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

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

答案 1 :(得分:5)

您不会覆盖静态方法。你隐藏它。有关详细信息,请参阅this answer

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

  1. 它们是little bit faster而非实例方法。另请参阅此msdn article,它提供了性能数据来支持这一点(内联静态调用平均值0.2 ns,静态调用平均值6.1ns,内联实例调用平均值1.1 ns,实例调用平均值6.8 ns)
  2. 写出来的冗长 - 不需要实例化一个类来获取它们(并且实例化也会影响性能)

答案 2 :(得分:5)

嗯,您无法覆盖静态方法。静态方法不能是虚拟的,因为它与类的实例无关。

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

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

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

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