views:

1089

answers:

6

I want to know if its possible to hide a base class property from a derived class:

Example:

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

I cannot make the the Docproperty private, because i want to instantiate the BaseDocument class elsewhere and use the property there. Thats will kill the idea of a property anyway.

One way to fix this would be to use a interface, say IDoc, which exposes DocPath property and make both the BaseDocument and DerivedDocument implement the interface. This will break their parent-child relationship though.

I can play with the new and override keywords, but thats not the right way either because the child still 'sees' the property

I tried using the 'sealed' keyword on the DocContent, but that does not seem to solve the problem either.

I understand that it 'breaks' inheritance, but I guess this scenario should be coming up frequently where a child needs to get everything else from the parent but one of two properties and the parent has been declared as a base class.

How can such scenarios be handled gracefully?

A: 

Just do this.

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

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

Or

public override DocContent 
{ 
    get { throw new NotImplementedException("Do not use this property!"); }
    set { throw new NotImplementedException("Do not use this property!"); } 
}
ChaosPandion
@Chaos: -1 becuase what you gave is a work around, the first one of which i think won't work, though i am not sure. I already posted better work arounds in my question. And the problem still remains because the derived class 'sees' the base class property. My question was related to hiding it completely.
desigeek
Thanks for commenting. I am just really having trouble understanding why you would want to do this.
ChaosPandion
A: 

I don't believe there is a good (or any) way to do this. You may have to break the hierarchy, or you could remove the DocContent property from BaseDocument, then derive two sepearate classes from BaseDocument, one which is your current DerivedDocument, and another which has the DocContent property.

Andy White
+3  A: 

I'm not sure inheritance would be the way to go here. Yes, you can hack around it by using the EditorBrowsableAttribute but I think the design should be rethought. One possible approach:

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

     }
}

Basically, use composition instead of inheritance, and program to an interface, not to an implementation.

BFree
Nice, that's a good solution
Andy White
You should also change the name DerivedDocument to prevent misunderstandings..
Gishu
+2  A: 

It sounds like you want to intentionally violate the Liskov Substitution Principle. Why bother with subclassing at all if it's not going to have the conventional inheritance semantics? Just make a separate class.

Alec
+1  A: 
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) ; 
    }
}
Anton Tykhyy
+1 : Lovely solution.
Kyle Rozendo
The only problem with this approach is that if you cast DerivedDocument to an IBaseDocument (which is a safe cast since it inhertis from BaseDocument which implements IBaseDocument) you'll now be able to see DocContent.
BFree
+2  A: 

You can do it easily if you don't mind having BaseDocument and DerivedDocument in different assemblies/projects.

Make DocContent internal. It'll be visible to everything in the same project as BaseDocument, but it won't be visible to DerivedDocument since that's in a different project. Of course, you'll need to make BaseDocument public (right now you have it as the default, internal).

In first project:

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

In second project that references first:

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

This solution has the advantage of not being a kludge. You can still use BaseDocument's DocContent property within BaseDocument's project. If you need to use DocContent in another project (separate from the project DerivedDocument is in), you can use the InternalsVisibleTo attribute to make DocContent visible to that assembly. (That, however, is in my opinion a kludge, albeit a very handy one in some scenarios.)

Kyralessa
+1 this is very nice but it breaks all of the idea of a class that should be in one file. Not the fact but it works.
Jonathan Shepherd
Sorry...it breaks *what* idea? It's two separate classes, one inheriting from the other. I don't know what idea you're talking about.
Kyralessa