【问题标题】:Hide inherited protected method隐藏继承的受保护方法
【发布时间】:2015-03-26 11:17:59
【问题描述】:

是否可以隐藏或阻止继承的 protected virtual 或 protected abstract 方法,以便进一步继承的类无法访问它们?

例如:

class Base<T>
{
    protected abstract T CreateInstance();
}

class Derivative : Base<Derivative>
{
    protected sealed override Derivative CreateInstance()
    {
        return new Derivative();
    }
}

class MoreDerivative : Derivative
{
    public MoreDerivative()
    {
        // cannot access CreateInstance here
    }
}

我不认为它是用语言实现的,但也许有注释或类似的东西。

【问题讨论】:

  • 你可以让Derivative 成为Base&lt;T&gt; 的包装器,而不是从它继承(选择要转发到子类的功能)。它会破坏继承链(显然),但任何其他方法都会破坏该契约。

标签: c# inheritance protected


【解决方案1】:

对于最终出现在这里的任何其他人,您也可以创建一个内部虚拟方法,只要您希望看到该方法的唯一类在同一个程序集中。

【讨论】:

    【解决方案2】:

    在尝试调用MoreDerivative 中的方法时,将Obsolete 注释添加到Derivative.CreateInstance 会导致编译器警告。如果调用与声明不在同一解决方案中,EditorBrowsable 将隐藏 IntelliSense 中的方法。

    [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
    [Obsolete("Method must only be invoked by the base class.", true)]
    protected sealed override Derivative CreateInstance() { /*...*/ }
    

    【讨论】:

      【解决方案3】:

      您可以使用委托按照您的意图完成某事:

      class Base<T>
      {
          private readonly Func<T> _createInstance;
      
          public Base(Func<T> createInstance)
          {
              _createInstance = createInstance;
          }
      
          private T CreateInstance()
          {
              return _createInstance();
          }
      }
      
      class Derivative : Base<Derivative>
      {
          public Derivative() : base(CreateInstance)
          {
      
          }
      
          private static Derivative CreateInstance()
          {
              return new Derivative();
          }
      }
      
      class MoreDerivative : Derivative
      {
          public MoreDerivative()
          {
              // cannot access CreateInstance here
          }
      }
      

      非静态实现:

      class Base<T>
      {
          private readonly Func<Base<T>, T> _createInstance;
      
          public Base(Func<Base<T>, T> createInstance)
          {
              _createInstance = createInstance;
          }
      
          private T CreateInstance()
          {
              return _createInstance(this);
          }
      }
      
      class Derivative : Base<Derivative>
      {
          public Derivative() : base(CreateInstance)
          {
      
          }
      
          private static Derivative CreateInstance(Base<Derivative> caller)
          {
              return ((Derivative)caller).CreateInstance();
          }
      
          private Derivative CreateInstance()
          {
              return new Derivative();
          }
      }
      
      class MoreDerivative : Derivative
      {
          public MoreDerivative()
          {
              // cannot access CreateInstance here
          }
      }
      

      【讨论】:

      • 你永远不会在基类中使用CreateInstance。您不妨将其删除。
      • @Dan 确实在某些情况下就足够了,但这里CreateInstance 是static,这不是问题所在。
      • @Servy,我主要包括它是为了与 OP 的签名粗略兼容(他可能是如何从 Base 中调用它的),但是是的,您可以直接从实现中使用委托基地。
      • @ominug,如果需要,可以使用 Func&lt;Base&lt;T&gt;, T&gt; 将其设为非静态,从 Base 传入 'this' 并让 Derived 实现适当地转换参数。
      【解决方案4】:

      不,这是不可能的。继续你的例子,MoreDerivative 仍然是Base&lt;Derivative&gt; 的子类型,Base&lt;&gt; 包含CreateInstance 方法。所以您必须有权访问该方法。如果你不这样做,你可以将对象转换为它的基类型然后访问它。

      【讨论】:

      • 显式接口实现允许这样的代码,如果A是一个接口而不是一个基类。
      【解决方案5】:

      没有。当您为一个类型定义一个成员时,您是说该类型及其所有子类型都将具有该成员。没有办法“撤销”它。这个假设是类型系统的一个组成部分。

      您可能想在这里考虑使用组合,而不是继承。创建一个具有Derivative 类型字段的类型,而不是从它继承。

      【讨论】:

      • 由于 protected 方法仅在派生类中可见,并且在派生类时需要显式给出基类的名称,为什么不能自定义受保护方法的可用性以进一步派生类?我认为 Liskov 的替换原则在这种情况下没有用,因为不可能替换碱基。请求的构造可用于在基类中注入功能,该功能只能由基类或定义类本身调用。
      猜你喜欢
      • 2020-09-09
      • 2016-03-17
      • 2016-09-04
      • 1970-01-01
      • 2019-02-10
      • 2010-11-17
      • 2013-12-14
      相关资源
      最近更新 更多