c#从派生类中隐藏一些基类的属性

时间:2009-08-27 04:26:41

标签: c# .net inheritance properties

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

示例:

    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上使用'sealed'关键字,但这似乎也无法解决问题。

我理解它“打破”继承,但我想这种情况应该经常出现在一个孩子需要从父母那里获得其他所有东西但只有一两个属性的情况。

如何妥善处理此类方案?

7 个答案:

答案 0 :(得分:3)

我不确定继承是否可以到达这里。是的,您可以使用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

     }
}

基本上,使用组合而不是继承,并编程到接口,而不是实现。

答案 1 :(得分:3)

如果您不介意在不同的程序集/项目中使用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对该程序集可见。 (但是,在我看来, 是一种kludge,虽然在某些情况下非常方便。)

答案 2 :(得分:2)

听起来你想故意违反Liskov替代原则。如果它不具备传统的继承语义,为什么还要继续使用子类?只需单独上课。

答案 3 :(得分:1)

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) ; 
    }
}

答案 4 :(得分:0)

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

答案 5 :(得分:0)

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

最美丽:将您的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 :(得分:-1)

就这样做。

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!"); } 
}