代码之家  ›  专栏  ›  技术社区  ›  James L

成员在C中使用新关键字隐藏的有效应用程序#

c#
  •  20
  • James L  · 技术社区  · 16 年前

    从版本1开始,我就一直在使用C,从未见过成员隐藏的有用之处。你知道吗?

    7 回复  |  直到 16 年前
        1
  •  15
  •   Eric Lippert    16 年前

    情景1:

    假设您正在为.NET 2.0设计运行库。你现在可以随意使用仿制药了。您有一个接口:

    interface IEnumerable 
    {
        IEnumerator GetEnumerator();
    }
    

    您希望创建一个新的界面

    interface IEnumerable<T> 
    {
        IEnumerator<T> GetEnumerator();
    }
    

    你现在有三个选择。

    1)使通用版本与非通用版本无关。

    2)使通用版本扩展非通用版本。现在您有两个方法,它们只在返回类型上有所不同。将新类型中getEnumerator的名称更改为getEnumerator2()。因为那很热。每个人都喜欢一个好的“2”方法。

    3)使通用版本扩展非通用版本。使新的和改进的方法隐藏现有方法,以便在需要时将其隐藏,但默认情况下隐藏。

    这些都是错误的选择。你会选择哪一个?我们选择了(3)。很好,这是一个选择;如果不隐藏,这个选择将不可用。

    现在,你可能会争辩说,这个隐藏的特殊例子是“不值得”的;如果是这样,你会怎么做呢?

    方法隐藏使暴露改进的接口成为可能,而不会在改进类型系统时导致损坏。

    情景2:

    你在佛罗布科工作。你产生了一个扩展了blobber的类blobber,它由blobco的好人提供给你。

    blobco忽略了在blobber上放置frobozzle()方法,但是您的客户喜欢使用frobozzle(),因此您向派生类frober添加了一个方法frobozzle()。

    Blobco意识到他们的客户想要冻结blobber,所以他们向blobber(基类)添加了一个非虚拟方法frobzzle()。

    现在你怎么办,佛罗布科的员工?

    1)删除frobeber上的frobozzle方法,从而破坏依赖于您的实现的客户。记住,blobco不知道如何使一个冒泡的人冒泡;他们只编写知道如何使一个冒泡的代码。

    2)向Blobco抱怨他们应该将方法变为虚拟的。希望有一天他们能做点什么。

    3)在派生类中隐藏它们的方法。

    方法隐藏有助于减轻脆弱的基类问题。

    进一步阅读:

    http://blogs.msdn.com/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx

        2
  •  11
  •   Marc Gravell    16 年前

    使返回类型更显式-例如 SqlConnection.CreateCommand 返回A SqlCommand 不是 DbCommand . 事实上,这似乎没有宣布 new 但那是我很少使用它的一次;大多数时候它是邪恶的。

    另一个用途:从成员中删除继承的属性。

        3
  •  5
  •   kemiller2002    16 年前

    我们有一个从WebControl类继承的类。当我们从3.5升级到4.0时,我们的一些属性(主要围绕onclick和javascript)发生了很大的变化。

    我们无法改变 AttributeCollection 类由 WebControl ,所以我们所做的是实现 属性收集 在我们的定制收藏中 属性收集 拥有我们自己的财产。

    访问代码都没有改变,我们能够正确地实现如何处理类中的属性。现在没人需要知道我们做了什么来解决这个问题。他们只需要知道 Attributes.Add 像平常一样,我们在引擎盖下修理东西。

        4
  •  2
  •   SLaks    16 年前

    当使用丰富的设计时经验制作控件时,通常需要隐藏现有属性以应用属性。

        5
  •  2
  •   dpurrington    16 年前

    一般来说,拒绝继承成员被认为是不好的做法。我唯一一次使用它是在生成的代码中,新成员在同一类层次结构中提供了更具体的类型。显式接口实现也是如此。

        6
  •  1
  •   Qwertie    16 年前

    有时,我会从基类库中的某个类派生一个类,其中的基类(出于性能原因)不使用虚拟函数。在这种情况下,使用“new”是有意义的。下面是一个例子(与MarcGravell所说的相匹配),一个强类型的weakreference:

    public class WeakReference<T> : System.WeakReference
    {
        public WeakReference(T target) : base(target) { }
        public WeakReference(T target, bool trackResurrection) : base(target, trackResurrection) { }
        #if !WindowsCE
        protected WeakReference(SerializationInfo info, StreamingContext context) : base(info, context) {}
        #endif
        public new T Target
        {
            get { return (T)base.Target; }
            set { base.Target = value; }
        }
    }
    

    在基类方法实际上是虚拟的情况下,我认为微软正在设想这样的情况:基类由一方实现,派生类由另一方实现。第二方添加了一个函数“foo”,然后第一方添加了另一个函数“foo”,它实际上做了一些不同的事情(因此覆盖并不合适)。然后,为了保持与第三方代码的兼容性,第二方保留了名为“foo”的函数,尽管它与基类版本没有直接关系。在这种情况下,第二方在其声明中添加了“新的”。

        7
  •  0
  •   to StackOverflow    16 年前
    1. 当一个类型的新版本实现一个公共可见的成员,该成员的名称与派生类型中使用的名称冲突时。

    2. 在派生的基类中隐藏不适当的实现。

      例如 KeyedCollection<TKey, TItem>.Contains(TItem item) 继承自 Collection<TItem> 因此是O(N)操作而不是O(1)操作, KeyedCollection<TKey, TItem>.Contains(TKey key) 通常提供。

      这可能令人困惑,因为天真的消费者可能认为两者可以互换。

      因此,实现“更好”的版本可能是合适的:

      public new bool Contains(TItem item)
      {
          if (item == null) throw new ArgumentNullException("item");
      
          return this.Contains(GetKeyForItem(item));
      }