【问题标题】:Is there ever a reason to hide inherited members in an interface?有没有理由在接口中隐藏继承的成员?
【发布时间】:2011-04-03 23:44:29
【问题描述】:

我了解从另一个类继承的类可能会通过使用 new 关键字来隐藏属性。然而,这隐藏了该属性的特定实现,所以我可以看到它是如何使用的。

是否有任何实际理由在实现其他接口的接口中隐藏成员?例如考虑下面的例子。 IChildInterface 实现IParentInterface,并隐藏PropertyA

interface IParentInterface
{
    string Name { get; set; }
    int PropertyA { get; set; }
    int PropertyB { get; set; }
}

interface IChildInterface : IParentInterface
{
    int PropertyA { get; set; }
    int PropertyC { get; set; }
}

【问题讨论】:

    标签: c# .net polymorphism interface


    【解决方案1】:

    是否有任何实际理由在实现其他接口的接口中隐藏成员?

    当然。 BCL 本身使用此模式的事实表明该模式是实用的。例如:

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

    IEnumerable&lt;T&gt; 的设计者希望与IEnumerable 向后兼容,但也希望确保在泛型接口上对GetEnumerator 的每次使用都称为泛型版本。在这种情况下,隐藏是适当的机制。

    有关方法隐藏的一些细节的额外讨论,请参阅:

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

    【讨论】:

      【解决方案2】:

      我发现隐藏基成员很有用的一种情况是,当你有一个基接口,它在属性上公开一个 getter,但派生接口想要公开一个 setter:

      public interface IBase
      {
         int MyProperty { get; }
      }
      
      public interface IDerive : IBase
      {
          // you need to specify the getter here too
          new int MyProperty { get; set; }
      }
      

      【讨论】:

        【解决方案3】:

        接口不能完全隐藏父接口,但实现类可以,这很有用。

        考虑一个类MyStringList,它是一个实现IList&lt;string&gt; 的只读列表。为简单起见,我们将其作为一个简单的传递:有些成员是毫无意义的,所以我们可以这样做:

        //implement this one implicitly, as it's useful.
        public int Count
        {
          return _list.Count;
        }
        //do a half-and-half on the indexer
        public string this[int index]
        {
          get
          {
            return _list[index];
          }
        }
        string IList<string>.this[int index]
        {
          get
          {
            return this[index];
          }
          set
          {
            throw new NotSupportedException("Collection is read-only.");
          }
        }
        //hide some pointless ones.
        bool ICollection<string>.IsReadOnly
        {
          get
          {
            return true;
          }
        }
        void IList<string>.Insert(int index, string item)
        {
          throw new NotSupportedException("Collection is read-only.");
        }
        void IList<string>.RemoveAt(int index)
        {
          throw new NotSupportedException("Collection is read-only.");
        }
        void ICollection<string>.Add(string item)
        {
          throw new NotSupportedException("Collection is read-only.");
        }
        void ICollection<string>.Clear()
        {
          throw new NotSupportedException("Collection is read-only.");
        }
        bool ICollection<string>.Remove(string item)
        {
          throw new NotSupportedException("Collection is read-only.");
        }
        

        处理MyStringListIList&lt;string&gt; 接口的人必须能够调用这些无意义的成员,但处理MyStringList 的人没有必要这样做。

        现在,有了这对类的可能,接口可以通过名称匹配父接口来强制对类进行这样的暗示。类示例是IEnumberable&lt;T&gt;,其中GetEnumerator() 与它继承的IEnumerable 匹配。因此,该类只能隐式实现一个,并且必须隐藏另一个或两者(因为一个总是可以将结果(IEnumerator&lt;T&gt;)转换为另一个(IEnumerator)的结果类型,那么最明智的行为是一般隐式实现IEnumberable&lt;T&gt; 版本,显式实现IEnumerable 一个(通常通过返回另一个的结果)。

        然而,虽然隐藏会强制至少隐藏一个,但没有什么可以强制选择隐式实现的特定选择(如果有的话),除了一个比另一个具有如此明显的优势以至于很少有人会这样做之外。

        【讨论】:

          【解决方案4】:

          在设计过程中绝不应刻意隐藏继承的成员。该语言允许方法隐藏,以防止祖先(在库的主要版本中)中的更改破坏碰巧已经定义了同名成员的后代。

          也就是说,有时用返回更具体类型的等效方法隐藏继承方法很方便。在这些情况下,您唯一要做的就是类型转换糖 - 注意不要更改方法的语义,因为调用者可能很容易调用祖先方法而不是您的方法。

          另请参阅:Is there ever a situation where derived class should hide …?

          【讨论】:

          • 我同意在类方面(包括你给出的例外),但我认为在接口方面有所不同。
          【解决方案5】:

          我想如果您要显式实现 IChildInterface,可能会出现您想要隐藏 PropertyA 的情况(也许?)

          【讨论】:

          • 但是由于 IChildInterface 实现了 IParentInterface 不会 IChildInterface 的任何实现(隐式或显式)也实现 IParentInterface?
          • 是的,我想现在我想想,你可能是对的。
          猜你喜欢
          • 2012-02-13
          • 2010-09-05
          • 2011-10-10
          • 1970-01-01
          • 2011-03-22
          • 1970-01-01
          • 1970-01-01
          • 2013-06-11
          • 1970-01-01
          相关资源
          最近更新 更多