13

Possible? Can you change the access of anything to anything else?

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
Mark Lalor
  • 7,820
  • 18
  • 67
  • 106

3 Answers3

18

No, you can hide a public member with a private method in a subclass, but you cannot override a public member with a private one in a subclass. And, in actually, it's not just a public/private thing, this applies to narrowing the access in general.

Revised: By hiding with a more restrictive access - in this case private access - you will still see the base class member from a base-class or sub-class reference, but it would defer to the new method when available from the new access level.

So in general, when you hide, the hide takes precedence when visible at its access level. Otherwise the original method is the one used.

public class BaseClass
{
    public virtual void A() { }

    public virtual void B() { }
}

public class SubClass
{
    // COMPILER ERROR, can't override to be more restrictive access
    private override void A() { }

    // LEGAL, you can HIDE the base class method, but which is chosen 
    // depends on level accessed from
    private new void B() { }
}

So SubClass.B() ONLY hides the base class methods when it is accessible. That is, if you call SubClass.B() inside of SubClass then it will take the hidden form of B(), but since B() is private, it is not visible to classes outside of itself, and thus they STILL see BaseClass.B().

The long and the short of it is:

1) You cannot override a method to be more restrictive (access wise). 2) You can hide a method with a more restrictive one, but it will only have an effect where that new access type is visible, otherwise the base one stands.

public class BaseClass
{
    public virtual void A() { }
    public virtual void B() { }
}

public class SubClass : BaseClass
{
    public virtual void A() { B(); }

    // legal, you can do this and B() is now hidden internally in SubClass,
    // but to outside world BaseClass's B() is still the one used.
    private new void B() { }
}

// ...

SubClass sc = new SubClass();
BaseClass bc = new BaseClass();

// both of these call BaseClass.B() because we are outside of class and can't
// see the hide SubClass.B().
sc.B();
bc.B();

// this calls SubClass.A(), which WILL call SubClass.B() because the hide
// SubClass.B() is visible within SubClass, and thus the hide hides BaseClass.B()
// for any calls inside of SubClass.
sc.A();
James Michael Hare
  • 37,767
  • 9
  • 73
  • 83
  • Are you sure about that? Seems like it would break Liskov's – Rag Aug 24 '11 at 15:58
  • You can do it. However, you could just cast it to `BaseClass` and call the method as if nothing happened. – Femaref Aug 24 '11 at 16:01
  • @Brian: Yep, hiding to make more restrictive is allowed. Compiles fine. Remember that the method still exists, and as long as you treat it as a base class reference, it is still there and runs, it just isn't visible from a sub-class (in the case of private hiding). Not saying it's always the best choice, OO wise, but it is possible in C#. – James Michael Hare Aug 24 '11 at 16:01
  • @Femaref: exactly, or access through a base-class reference of course. – James Michael Hare Aug 24 '11 at 16:02
  • Oh, from reading the main text of your answer for some reason I thought you were saying that the one marked "illegal" in your example code is legal. – Rag Aug 24 '11 at 16:04
4

Nope.

A typical way to deal with this is to throw a NotImplementedException or something to that effect.

CodingGorilla
  • 19,612
  • 4
  • 45
  • 65
  • 6
    `NotImplementedException` implies something omitted by mistake. `NotSupportedException` implies something omitted by design (and possibly *still* by mistake, as the case may be). – Anthony Pegram Aug 24 '11 at 16:05
2

You cannot narrow or widen the visibility of an overriden member. However, you can define another method with the new keyword, which can give you a new method with the same name, but which is incompatible in terms of polymorphism.

public class A : B
{
    public new void Foo()
    {
        base.Foo();
    }
}
Rag
  • 6,405
  • 2
  • 31
  • 38
  • 2
    That's not an over **ride**, it's an over **write**. If you cast this class to `B`, the method will be available, even though you overwrote it in `A`. – Femaref Aug 24 '11 at 15:59