c # скрыть от дервидированных классов некоторые свойства базового класса - PullRequest
0 голосов
/ 27 августа 2009

Я хочу знать, возможно ли скрыть свойство базового класса от производного класса:

Пример:

    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 реализовать интерфейс. Это нарушит их отношения между родителями и детьми.

Я могу поиграть с новыми и переопределить ключевые слова, но это неправильный путь, потому что ребенок все еще «видит» свойство

Я пытался использовать ключевое слово «sealed» в DocContent, но, похоже, это тоже не решает проблему.

Я понимаю, что это «нарушает» наследование, но я предполагаю, что этот сценарий должен часто встречаться, когда ребенку нужно получить все остальное от родителя, кроме одного или двух свойств.

Как можно изящно обрабатывать такие сценарии?

Ответы [ 7 ]

3 голосов
/ 27 августа 2009

Вы можете сделать это легко, если не возражаете против использования 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
    }
}

Преимущество этого решения состоит в том, что он не является кладжем. Вы по-прежнему можете использовать свойство DocContent BaseDocument в проекте BaseDocument. Если вам нужно использовать DocContent в другом проекте (отдельно от проекта, в котором находится DerivedDocument), вы можете использовать атрибут InternalsVisibleTo, чтобы сделать DocContent видимым для этой сборки. (Однако, на мой взгляд, является клуджем, хотя в некоторых сценариях он очень удобен.)

3 голосов
/ 27 августа 2009

Я не уверен, что наследство было бы способом пойти сюда. Да, вы можете взломать его с помощью 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 голосов
/ 27 августа 2009

Похоже, вы хотите преднамеренно нарушить принцип замещения Лискова. Зачем вообще заниматься подклассами, если у них не будет традиционной семантики наследования? Просто сделайте отдельный класс.

1 голос
/ 27 августа 2009
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) ; 
    }
}
0 голосов
/ 29 апреля 2013

Поздняя реакция, но есть несколько способов сделать это.

Самый красивый: поместите свой класс 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
  }
}
0 голосов
/ 27 августа 2009

Я не верю, что есть хороший (или любой) способ сделать это. Возможно, вам придется нарушить иерархию, или вы можете удалить свойство DocContent из BaseDocument, а затем получить два отдельных класса из BaseDocument, один из которых является вашим текущим DerivedDocument, а другой - со свойством DocContent.

0 голосов
/ 27 августа 2009

Просто сделай это.

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