【问题标题】:Use new keyword if hiding was intended如果打算隐藏,请使用新关键字
【发布时间】:2014-07-24 14:36:23
【问题描述】:

我有以下 sn-p 代码在 VS2008 中生成“如果有意隐藏则使用新关键字”警告:

public double Foo(double param)
{
   return base.Foo(param);
}

基类中的Foo() 函数是受保护的,我想通过将它放在包装类中仅出于单元测试的目的将它公开给单元测试。 IE。包装类不会用于其他任何事情。所以我的一个问题是:这是公认的做法吗?

回到new 警告。 为什么在这种情况下我必须新建覆盖函数?

【问题讨论】:

标签: c# inheritance warnings new-operator


【解决方案1】:

new 清楚地表明你知道你正在践踏现有的方法。由于现有代码是 protected,因此没什么大不了的 - 您可以安全地添加 new 以停止它的抱怨。

当你的方法做了不同的事情时,差异就出现了;任何引用派生类并调用Foo()的变量都会做一些不同的事情(即使使用相同的对象)作为引用base类并调用Foo()的变量:

SomeDerived obj = new SomeDerived();
obj.Foo(); // runs the new code
SomeBase objBase = obj; // still the same object
objBase.Foo(); // runs the old code

这显然会对知道SomeDerived 并调用Foo() 的任何现有代码产生影响——即它现在运行的是完全不同的方法。

另外,请注意您可以将其标记为protected internal,并使用[InternalsVisibleTo] 来提供对单元测试的访问(这是[InternalsVisibleTo] 的最常见用法;然后您的单元测试可以直接访问它而无需派生类。

【讨论】:

    【解决方案2】:

    关键是您没有覆盖该方法。你在隐藏它。如果要覆盖它,则需要 override 关键字(此时,除非它是虚拟的,否则编译器会抱怨,因为您无法覆盖非虚拟方法。 p>

    您使用 new 关键字告诉编译器和任何阅读代码的人,“没关系,我知道这只是隐藏基本方法而不是覆盖它 - 这就是我的意思。”

    坦率地说,我认为隐藏方法很少是一个好主意 - 我会使用不同的方法名称,就像 Craig 建议的那样 - 但这是一个不同的讨论。

    【讨论】:

    • 我发现隐藏有用的一个地方是,当我有一个接口,它的实现使用我不想更改的基类,只使用它的方法。这样,我可以在使用接口实例的对象中使用基类方法,而不是实现接口的类,例如Ctor(IFoo foo){int x = foo.OriginalBaseMethod();} 而不是 Ctor(Foo foo){int x = foo.OriginalBaseMethod();}
    【解决方案3】:

    您正在更改没有名称的可见性。调用您的函数 TestFoo ,它将起作用。是的,恕我直言,因此可以接受子类化。

    【讨论】:

      【解决方案4】:

      您总是会发现一些棘手的情况,其中new 关键字可以用于隐藏,而大多数情况下可以避免。

      但是,最近我真的需要这个关键字,主要是因为该语言缺少一些其他适当的合成器功能来完成现有的访问器,例如:

      如果你考虑一个老式的类,比如:

      KeyedCollection<TKey, TItem>
      

      您会注意到访问项目槽索引的访问器是:

      TItem this[Int32 index] { get; set; }
      

      同时拥有{ get; set; },由于ICollection&lt;T&gt;Collection&lt;T&gt; 的继承,它们当然是强制性的,但是只有一个{ get; } 用于通过它们的键访问项目(我对此设计有一些猜测这有很多原因,所以请注意,我选择KeyedCollection&lt;TKey, TItem&gt;) 只是为了说明)。

      无论如何,密钥访问只有一个 getter:

      TItem this[TKey key] { get; }
      

      但是如果我想添加{ set; } 支持呢,从技术上讲,这并不是那么愚蠢,特别是如果你继续从以前的属性定义中推理,它只是一种方法......唯一的方法是显式地实现另一个虚拟接口,但是当你想要隐式时,你必须想出new 关键字,我隐藏了访问器定义,保留了get;基本定义,只需添加一组塞满一些个人物品的集合即可使其正常工作。

      我认为对于这个非常具体的场景,这个关键字是完全适用的,特别是在没有带入{ get; } 部分的上下文中。

        public new TItem this[TKey key]
        { 
            get { return base... }
            set { ... }
        }
      

      这几乎是避免此类警告的唯一技巧,因为编译器会提示您可能在没有意识到自己在做什么的情况下隐藏。

      【讨论】:

        猜你喜欢
        • 2013-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多