views:

1662

answers:

8

The essence of the problem is, given a class hierarchy like this:

class A
{
    protected void MethodToExpose()
    {}

    protected void MethodToHide(object param)
    {}
}

class B : A
{
    new private void MethodToHide(object param)
    {}

    protected void NewMethodInB()
    {}
}

class C : B
{
    public void DoSomething()
    {
        base.MethodToHide("the parameter"); // This still calls A.MethodToHide()
        base.MethodToExpose(); // This calls A.MethodToExpose(), but that's ok
        base.NewMethodInB();
    }
}

How can I prevent any classes that inherit from class "B" from seeing the method A.MethodToHide()? In C++, this was easy enough by using a declaration such as class B : private A, but this syntax is not valid in C#.

For those interested (or wondering what I'm really trying to do), what we're trying to do is create a wrapper for for Rhino.Commons.NHRepository that hides the methods we don't want to expose to our group of developers, so we can have a cookie-cutter way of developing our app that new developers can easily follow. So yes, I believe the "Is-A" test is valid for the whole chain (WidgetRepository Is-A BaseRepository Is-A NHRepository).

Edit: I should have mentioned, for the sake of argument, that class A is an API class outside of our control. Otherwise the problem gets considerably easier.

+8  A: 

If you want to custom tailor a set of features, I'd say you want to make a wrapper rather than inherit the functionality. I don't know of a way to do what you want in C# either.

Think about it, what if some code outside your control wants this NHRepository instance for something... but you've removed the functionality from the function it needs in your child class (which you would send in, since that's your only NHRepository instance.) Everything goes boom. That's why I don't think it's even possible to do without some ugly hack.

Blixt
+1 I'd bet on doing a wrapper as well, rather than inheritance. Instead of focusing on what you want to hide, you can focus on what you want to expose.
Will Eddins
I think the closest fit would be to override or declare new methods in the subclass that throw NotSupportedExceptions--definately ugly!
STW
@Yoooder: I doubt all the methods are `virtual` so they can't be overridden (and overriding could mess up the behavior of the whole class anyways) and attempting to hide them with `new` appears to be something he already tried (see his example.)
Blixt
A: 

Your code in derived class B won't hide the base method from all derived types, only itself. You would have to set the method to private in the base. The only way around this issue is to create another base class that does not expose this method.

James
+5  A: 

You can't do it and preserve the hierarchy. If possible, you should create interfaces that define your ideal, then subclass the bases classes and implement the interfaces. reference the interfaces only (not the base class types) in your code.

The Adapter pattern was created specifically to solve the problem of how to use a framework when its API doesn't line up exactly with your needs.

Michael Meadows
+1: I like this solution! As long as developers stick with the interface and don't explicitly cast it to the custom class, they won't have access to anything but what is specified in the interface.
Blixt
That's a slick idea. This is along the lines of what we're already doing (using NHibernate, MVC, Dependency Injection, ...), so we already have interfaces for the repositories (class C). That keeps the clients of Class C in the dark about what's under-the-covers. All that's left to worry about is how C is implemented. In our case, there will be many "C"-level child classes (repositories for different objects). So our ideal is probably having B be a wrapper/adapter to A. Unfortunately, A has a lot of methods to decide if we want to hide or expose in B.
Ogre Psalm33
+1  A: 

C# does not have a concept similar to protected or private inheritance in C++.

Your best option is to aggregate an instance of the class and expose the set of methods you are interested in you consumers having access to.

Although in your case I don't think it's possible, you could look into creating an interface that exposes just the common functionality that you want consumers be work with so that your wrapper can be substitutable in some instances for it's aggregate.

LBushkin
+1  A: 

I never knew you could do that in C++ though I don't know much about C++. I'm afraid that I agree with Blixt that a wrapper class is probably how I'd implement this.

It might work (but I'm not sure) to simply override the function and throw an exception upon a call....

Frank V
This does work. My fellow developer is leaning towards this solution, but I'm not satisfied because it doesn't seem that clean.
Ogre Psalm33
C++ is the definitive "you can do anything you want" language, with a lot of surprising flexibility. Including the flexibility to shoot yourself in the foot, hang yourself, run yourself over with a bus...
Ogre Psalm33
+3  A: 

If you are using Visual Studio, you can hide the methods/properties from intelliprompt with this attribute:

class A
{
    protected void MethodToExpose()
    {}

    [System.ComponentModel.EditorBrowsable(EditorBrowsableState.Never)]
    protected void MethodToHide(object param)
    {}
}

It won't actually get rid of the function, but if they are just your internal people. It might be close enough.

Jake Pearson
I forgot to mention when I first posted that "class A" is an API class outside of our control. So modifying class A is out. However, I'll play around with this. [System.ComponentModel.EditorBrowsable(...)] appears to be a handy feature that may come in useful at some point!
Ogre Psalm33
You could probably add on the attribute down in class B.
Jake Pearson
+1  A: 

As far as I know you can't hide it in the way you want. I think you could prevent it from being used in any practical manner though:

class B : A
{
    public new void MethodToHide(object param)
    { 
        throw new DontUseThisMethodException();
    }

    protected void NewMethodInB()
    {}
}

Not the nicest thing to do though, so you would probably want to solve it in some other way...

Fredrik Mörk
My coworker decided to use this approach. It's nicer to hide it at compile time instead of run-time, though.
Ogre Psalm33
A: 

Actually you CAN hide A's method from C if you would have defined B's method as accessible from C.

The only problem with your code is that you use "private" on your hiding declaration... if you use protected or public you would not have any issues and it would operate as you expect. I do this all the time with fields.

KDogg
I think I see what you're trying to say, but I really don't want class C to see any version of MethodToHide(param), whether it's inherited from B or A. A coworker's solution is along the lines of what you suggested, though. He overrides MethodToHide(param) in B, but has the extra step of making B.MethodToHide(param) throw a NotImplementedException. Similar to Fredrick's solution.
Ogre Psalm33