【问题标题】:c# hide from dervied classes some properties of base classc#从派生类中隐藏基类的一些属性
【发布时间】:2010-11-23 06:08:27
【问题描述】:

我想知道是否可以从派生类中隐藏基类属性:

例子:

    class BaseDocument
    {
        public string DocPath{get; set;}
        public string DocContent{get; set;}
    } 

    class DerviedDocument: BaseDocument
    {
     //this class should not get the DocContent property
        public Test()
        {
           DerivedDocument d = new DerivedDocument();
           d.//intellisense should only show me DocPath
             //I do not want this class to see the DocContent property
        }
    }

我无法将 DocContent 属性设为私有,因为我想在其他地方实例化 BaseDocument 类并在那里使用该属性。无论如何,这将扼杀财产的想法。

解决此问题的一种方法是使用接口,例如 IDoc,它公开 DocPath 属性并使 BaseDocument 和 DerivedDocument 都实现该接口。但这会破坏他们的父子关系。

我可以使用 new 和 override 关键字,但这也不是正确的方法,因为孩子仍然“看到”该属性

我尝试在 DocContent 上使用“密封”关键字,但这似乎也不能解决问题。

我知道它“破坏”了继承,但我想这种情况应该经常出现,孩子需要从父母那里获取所有其他东西,但只有一两个属性。

如何优雅地处理这样的场景?

【问题讨论】:

  • 我有一个类似于问题的现有场景。另外,我只是想知道!
  • 就像其他人提到的......如果是这种情况,你不应该从基础派生。派生类应该完全支持基类接口。如果我的程序使用 CBase,它的行为应该不会改变,即使我为 CBase 提供任何 CDerived - objectmentor.com/resources/articles/lsp.pdf
  • -1 表示无效问题。首先,多年来,C# 和所有面向对象的编程语言都建立在标准模式集之上。 “Public”的意思是真正的公众,应该随处可见。你不能有一个公共的地方,它可以在某个地方变成私有的,尝试通过界面、其他模式或内部关键字来解决答案,但试着理解系统的设计是通用的,对于每个人来说,它不能为你的小时间需求而改变。
  • @Akash:如果你再次阅读这个问题,我已经提到我理解使用这种方法不是一个好的设计,我提供了我自己的解决方案。但是,如果您已经从遗留代码中获得了类似的东西,而您无法更改并且被该基类所困怎么办?那你怎么处理。那是我的问题。所以我认为就情况的实用性而言,这仍然是一个有效的问题。

标签: c# .net inheritance properties


【解决方案1】:

我不确定继承是否会成为这里的路。是的,您可以使用EditorBrowsableAttribute 解决它,但我认为应该重新考虑设计。一种可能的方法:

public interface IDoc
{
   DocPath{get;set;}
}

class BaseDocument : IDoc
{
     public DocPath{get; set;}
     public DocContent{get; set;}
} 

class DerviedDocument
{
    public DerivedDocument(IDoc doc)
    {
        this.Doc = doc;
    }

    public IDoc Doc{get;set;}

     public Test()
     {
        DerivedDocument d = new DerivedDocument(new BaseDocument());
        d.//here you will only see d.IDoc which only exposes DocPath

     }
}

基本上,使用组合而不是继承,并且针对接口而不是实现进行编程。

【讨论】:

    【解决方案2】:

    如果您不介意在不同的程序集/项目中使用 BaseDocument 和 DerivedDocument,您可以轻松完成。

    将 DocContent 设为内部。它对与 BaseDocument 相同的项目中的所有内容都可见,但对 DerivedDocument 不可见,因为它位于不同的项目中。当然,您需要将 BaseDocument 公开(现在您将其作为默认的内部文档)。

    在第一个项目中:

    public class BaseDocument
    {
        public string DocPath {get; set;}
        internal string DocContent {get; set;}
    }
    

    在第一个引用的第二个项目中:

    class DerivedDocument : FirstProject.BaseDocument
    {
        public Test()
        {
           DerivedDocument d = new DerivedDocument();
           d.  //intellisense shows DocPath, but not DocContent
        }
    }
    

    此解决方案的优点是不是杂牌。您仍然可以在 BaseDocument 的项目中使用 BaseDocument 的 DocContent 属性。如果您需要在另一个项目中使用 DocContent(与 DerivedDocument 所在的项目分开),您可以使用 InternalsVisibleTo 属性使 DocContent 对该程序集可见。 (然而,在我看来,是的一个组合,尽管在某些情况下非常方便。)

    【讨论】:

    • +1 这非常好,但它打破了应该在一个文件中的类的所有想法。不是事实,但它有效。
    • 对不起...它打破了什么的想法?它是两个独立的类,一个继承自另一个。我不知道你在说什么想法。
    【解决方案3】:

    听起来你想故意违反里氏替换原则。如果它不具有传统的继承语义,为什么还要为子类化而烦恼呢?只需创建一个单独的类。

    【讨论】:

      【解决方案4】:
      interface IBaseDocument
      {
          string DocPath    { get ; set ; }
          string DocContent { get ; set ; }
      } 
      
      class BaseDocument : IBaseDocument
      {
          public string DocPath { get ; set ; } // implement normally
      
          private string MyDocContent ;   // use this in BaseDocument
          string IBaseDocument.DocContent // implement explicitly
          { 
              get { return MyDocContent  ; } 
              set { MyDocContent = value ; } 
          }
      } 
      
      class DerviedDocument : BaseDocument
      {
          public void Test ()
          {
             // error: The name 'DocContent' does not exist in the current context
             Console.WriteLine (DocContent) ; 
          }
      }
      

      【讨论】:

      • 这种方法的唯一问题是,如果您将 DerivedDocument 转换为 IBaseDocument(这是一种安全转换,因为它继承自实现 IBaseDocument 的 BaseDocument),您现在将能够看到 DocContent。跨度>
      【解决方案5】:

      反应迟缓,但有几种方法可以做到这一点。

      最漂亮:将Base 类放在单独的程序集中,并将属性DocContent 标记为internal 而不是public:

      class BaseDocument
      {
          public string DocPath{get; set;}
          internal string DocContent{get; set;} //won't be visible outside the assembly
      }
      

      或者使用attributes 对源代码编辑器隐藏属性:

      class BaseDocument
      {
          public string DocPath{get; set;}
          public string DocContent{get; set;}
      } 
      
      class DerviedDocument: BaseDocument
      {
         //this class should not get the DocContent property
      
        [Browsable(false), EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
        public new string DocContent{ get; set; }
      
        public Test()
        {
           DerivedDocument d = new DerivedDocument();
           d.//intellisense will only show me DocPath
           //I do not want this class to see the DocContent property
        }
      }
      

      【讨论】:

        【解决方案6】:

        我不相信有一个好的(或任何)方法可以做到这一点。您可能必须打破层次结构,或者您可以从 BaseDocument 中删除 DocContent 属性,然后从 BaseDocument 派生两个单独的类,一个是您当前的 DerivedDocument,另一个具有 DocContent 属性。

        【讨论】:

          【解决方案7】:

          就这样做吧。

          class BaseDocument
          {
              public DocPath{get; set;}
              public virtual DocContent{get; set;}
          } 
          
          class DerviedDocument: BaseDocument
          {
              public override DocContent 
              { 
                  get { return null; }
                  set { } 
              }    
          }
          

          或者

          public override DocContent 
          { 
              get { throw new NotImplementedException("Do not use this property!"); }
              set { throw new NotImplementedException("Do not use this property!"); } 
          } 
          

          【讨论】:

          • @Chaos:-1 因为你给出的是一种解决方法,我认为第一个方法行不通,虽然我不确定。我已经在我的问题中发布了更好的解决方法。而且问题仍然存在,因为派生类“看到”了基类属性。我的问题与完全隐藏有关。
          • 感谢您的评论。我真的很难理解你为什么要这样做。
          猜你喜欢
          • 2010-11-27
          • 2013-06-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-03
          • 2015-04-09
          • 1970-01-01
          相关资源
          最近更新 更多