【问题标题】:Why is it considered method hiding if a parent and child class have a static method with the same name?如果父类和子类具有同名的静态方法,为什么会认为方法隐藏?
【发布时间】:2011-09-01 20:07:30
【问题描述】:

如果您声明的继承层次结构中父类和子类都具有相同名称和参数的静态方法*,Visual Studio 将引发警告CS0108

例子:

public class BaseClass
{
    public static void DoSomething()
    {
    }
}

public class SubClass : BaseClass
{
    public static void DoSomething()
    {
    }
}

: warning CS0108: 'SubClass.DoSomething()' hides inherited member 'BaseClass.DoSomething()'. Use the new keyword if hiding was intended.

为什么这被认为是隐藏方法?这两种方法都不涉及继承层次结构,只能使用类名调用:

BaseClass.DoSomething();
SubClass.DoSomething();

或者,在类本身中不合格。无论哪种情况,调用哪个方法都没有歧义(即没有“隐藏”)。

*有趣的是,这些方法可能因返回类型而异,但仍会产生相同的警告。但是,如果方法参数类型不同,则不会生成警告。

请注意,我并不是要为静态继承或任何其他此类废话创建论据或讨论。

【问题讨论】:

  • 有一点是肯定的——方法在 c# 中不因返回类型而异。静态不是这种情况,每种方法都是如此。它们也没有区别于它们的访问修饰符

标签: c# .net inheritance static


【解决方案1】:

如果没有明确指出类名,子类的成员将无法从 BaseClass 访问 DoSomething。所以它实际上对子类的成员“隐藏”,但仍然可以访问。

例如:

public class SubClass : BaseClass
{
    public static void DoSomething()
    {
    }

    public static void DoSomethingElse()
    {
        DoSomething(); // Calls SubClass
        BaseClass.DoSomething(); // Calls BaseClass
    }
}

【讨论】:

  • 很好的例子,虽然不如非静态虚拟方法的理由那么令人信服。如果在 SubSubClass 中声明 DoSomethingElse(),也许更好的例子。
  • @Travis - 好点。你走的继承链越往下,它可能就越混乱:-)
【解决方案2】:

这只是一个警告。编译器只是想确保您有意使用相同的方法名称。

【讨论】:

  • 如果我没有故意使用相同的方法名,有什么问题?
  • 我不明白你的意思。通过显式指定“new”,您是在告诉编译器您打算使用相同的方法签名。
  • 我认为 InBetween 在他们的回答中解释得最好,包括您的基本假设似乎是错误的。
  • 考虑非静态方法。如果我有两个同名的方法,并且我正在调用,则可能存在歧义。在静态情况下,这种模棱两可并不容易存在(尽管请参阅@CodeNaked 的回复以了解它可能存在的类似示例)
【解决方案3】:

为什么这被认为是隐藏方法?这两种方法都不涉及继承层次结构,只能通过类名调用。

那不是真的。你可以从任何继承的类名中调用 DoSomething:

public Class A
{
     public static void C() {...}
}

public Class B: A
{

}

B.C() // Valid call!

这就是为什么你在 B 中声明具有相同签名的方法时隐藏 C()。

希望这会有所帮助。

【讨论】:

  • 我考虑过这个,但看起来很愚蠢。调用 B.C() 确实有效,但意图值得怀疑。如果之后在 B 中引入方法 C,重新编译会更改它以调用新引入的方法。注意,如果你不重新编译 B.C() 调用(如果它在不同的程序集中等),它仍然会引用 A.C()。
  • 我不确定我是否理解你。这正是编译器在您实现 B.C() 时警告您的原因:您可能会在不知不觉中通过 B 调用 B.C() 时错误地使任何期望 A.C() 的调用者。如果您添加“新”关键字,您将明确让编译器知道您要隐藏 A 的 C() 实现,并使来自 B 的任何调用者解析为 BC()(请注意,AC() 仍将执行原始实现A)。
  • 也许更好的问题是“为什么 B.C() 甚至可以编译?”首先。 =) 您的论点对于实例方法是有意义的,因为它们是继承的。静态方法不是,尽管通过允许像 B.C() 这样的东西进行编译(当 B 没有声明 C 方法时)会产生这种错觉。我认为@CodeNaked 的回答反映了一个更实际的例子。
  • 为什么 B.C() 编译是一个很好的观点,但这不是手头的问题。事实是它确实可以编译,因此警告是有道理的。否则,您将隐藏 A 中定义的方法,根本没有反馈。警告显然是更好的选择。
【解决方案4】:

Visual Studio 和 Philippe 表示这是一个警告,因此您的代码将编译并运行。

但是,“CodeNaked”很好地展示了它为何被隐藏。此代码编译时不会抛出错误或警告。感谢“CodeNaked”

public class BaseClass {
    public virtual void DoSomething() {
    }
}

public class SubClass : BaseClass {
    public override void DoSomething() {

    }

    public void DoSomethingElse() {
        DoSomething(); // Calls SubClass
        base.DoSomething(); // Calls BaseClass
    }
}

编辑: 使用 Travis 的代码,我可以执行以下操作:
BaseClass.DoSomething();
子类.DoSomething();

而且效果很好。事情是你可能想知道为什么 SubClass 继承自 BaseClass 并且两者都实现了相同的静态方法。实际上这不是真的,两个类都实现了可能完全不同但名称相同的方法。这可能会令人困惑。

【讨论】:

  • 我认为混淆与静态类有关,因此在任何地方删除该关键字并不能真正帮助回答问题。如果您将方法全部设为静态,我认为您会收到一些警告甚至错误。
  • 这是一个很好的例子——我问了关于静态方法的问题。具有虚拟/非虚拟方法的实例方法案例完全有意义。静态是它有点令人毛骨悚然的地方。
  • 使用上面的代码,如果你添加了 static 关键字,你会得到错误并且代码不会编译。静态类和方法的问题是不必先实例化该类。
猜你喜欢
  • 1970-01-01
  • 2016-07-04
  • 1970-01-01
  • 2011-09-16
  • 2015-12-16
  • 2015-06-08
  • 2011-05-04
  • 2021-08-24
  • 1970-01-01
相关资源
最近更新 更多