【问题标题】:Can a static method be overridden in C#?可以在 C# 中重写静态方法吗?
【发布时间】:2013-01-27 12:09:50
【问题描述】:

有人告诉我static 方法隐含为final,因此不能被覆盖。真的吗?

  1. 谁能给出一个更好的覆盖静态方法的例子?

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

【问题讨论】:

  • 不,它们不能被覆盖。它们与类相关联,而不是与对象相关联。
  • 真正使用:你可以在没有类实例的情况下调用静态方法。
  • 谢谢。我了解what a static method is,这是 SLaks 给出的最佳示例。因此,对于我关于覆盖静态方法的问题(如果默认情况下它是最终的,而不是用户使其成为最终的) - 这是否意味着拥有静态的此类的任何子类都不能定义具有相同签名的静态方法?
  • 顺便说一句,这似乎是我试卷中提出的一个问题:P
  • 我不认为你是我的同学 :D 但很高兴成为。 PS:如果注意到我的问题的新手风格,是的,我正处于学习正确理论的阶段 - 我意识到没有他们我只能编写算法代码但无法正确解释:)跨度>

标签: c# overriding static-methods final


【解决方案1】:

(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

因为静态对实例不起作用,所以您总是明确指定 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

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

【讨论】:

  • 感谢你给我这个覆盖的例子。是的,我正在尝试代码。所以要做到这一点,1) 我们可以像任何其他非静态类一样子类化一个静态类? 2)我们可以使用静态方法而不覆盖父类静态方法,而是使用New关键字隐藏它们。
  • 我添加了更多解释和示例。 (1) 不,您不能对静态类进行子类化,但可以隐藏静态成员。 (2) 是的,您应该尝试第二个示例,它说明了它的行为方式。
  • 这个 Foo 酒吧的废话什么时候结束???停止使用 FoorBar 为例,在每种情况下, Bar 和 Foo 都是类或子类或函数或方法。那有什么意义???只需将 Animals 用于子类化和用于覆盖的操作。 10x
  • 如果我应用您的第一个示例,我会得到:'Bar' member names cannot be the same as their enclosing typesBar.Bar 甚至无法工作。
【解决方案2】:

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

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

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

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

静态方法也不能实现接口;如果这个类正在实现一个 IRolesService 接口,那么我认为该方法根本不应该是静态的。最好设计一个实例方法,这样您就可以在准备好时将您的 MockRoleService 换成真实的服务

【讨论】:

  • 谢谢。这对我来说有点高水平,但在此过程中我会明白的:) PS:在这种情况下,我绝对想上你的课。找到this post too in Java context.
【解决方案3】:

您不会覆盖静态方法。你把它藏起来。请参阅this answer 了解更多信息。

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

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

【讨论】:

  • 我对实例方法没有任何问题。我了解到static Class 不能被实例化。但是您提到“静态方法是它仅在您的应用程序中实例化一次”..所以我现在很困惑。你是指Using System.Math; 说静态方法被实例化了吗?我一直在同一个类中多次使用 Math 类成员 Math.Abs​​() ,甚至一次都没有实例化它们。 1) 那么您能否澄清一下“实例化一次” 的含义? 2)静态类可以是子类吗?子类是静态类有意义吗?
  • 查看我的编辑。我不应该在静态方法中使用术语“实例化”。更正确的说法是只创建一次。
  • 所有方法只被“创建”一次。即使是非静态方法也只存在一份代码副本(IL 代码在编译时创建并在运行时一次转换为机器代码)。不要混淆代码和数据!非静态方法只能通过对象的实例调用,但这是因为传递给它的隐藏的“this”指针。代码本身是“静态的”,因为它是固定的和单例的。
  • @MatthewWatson 感谢您的更正。我删除了违规部分并更新了答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-12
  • 1970-01-01
  • 1970-01-01
  • 2011-01-29
相关资源
最近更新 更多