Why can't we change access modifier while overriding methods in C#?
Asked Answered
I

8

51

In C#, we can not change access modifier while overriding a method from base class. e.g.

Class Base
{
   **protected** string foo()
   {
       return "Base";
   }
}

Class Derived : Base
{
   **public** override string foo()
   {
       return "Derived";
   }
}

This is not valid in C#, It will give compile time error.

I want to know the reason, why it's not allowed. Is there any technical problem or can it lead to something which is not consistent in terms of access restriction???

Inch answered 4/6, 2011 at 13:8 Comment(0)
H
33

Changing the access modifier of a method in a derived type is pointless that's why it's not allowed:

Case 1: Override with a more restrictive access

This case is obviously not allowed due to the following situation:

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

class Derived: Base
{
    protected override void A()
}

Now we could say:

List<Base> list;
list.Add(new Derived());
list[0].A() //Runtime access exception

Case 2: Overriding with a less restrictive access modifier

What is the point? Hide the method and you are done. Obviously if someone calls through the base type they will not have access to the new method defined in the derived type but that is consistent with how the author of the base type wanted things to be so you have no "right" to change that. If you want the specifics of the derived class call from the derived class, in which case the new method works perfectly fine.

EDIT: Expanding case 2

What I am trying to say in case 2, is that you already have the means to change accessibility of any method (virtual or not) if you want to change accessibility.

Consider the following code:

public class Base
{
    protected virtual string WhoAmI()
    {
        return "Base";
    }
}

public class Derived : Base
{
    public new virtual string WhoAmI()
    {
        return "Derived";
    }
}

public class AnotherDerived : Derived
{
    public override string WhoAmI()
    {
        return "AnotherDerived";
    }
}

With the new keyword you have effectively created a new virtual method for your Derived class with the same name and signature. Take note that it is ALLOWED to declare a new method virtual, so any class deriving from Derived will be allowed to override it.

What is not allowed is to have someone do the following:

 Base newBaseObject = new Derived();
 newBaseObject.WhoAmI() //WhoAmI is not accessible.

But this fact has nothing to do with being able to override WhoAmI() or not. Whatever the case this situation can never be because Base does not declare a public WhoAmI().

So in a theoretical C# where Derived.WhoAmI() could override Base.WhoAmI() there is no practical benefits in doing so because you will never be able to call the virtual method from the base class anyways, so the new option already meets your requirements.

I hope this makes it clearer.

Hoodoo answered 4/6, 2011 at 13:52 Comment(17)
Hi InBetween, Thanks for help. I am very much convinced about the case 1 u explained here. But m still confused for Case 2. When I am overriding a method, Anyway I am overriding(hiding) behavior of the base class method. So there is nothing to change base class things.Inch
I do not understand how you say “there is no practical benefits in doing so because you will never be able to call the virtual method from the base class anyways”. It is very common for a base class to define a protected virtual method to enable the subclass to change behavior exhibited by implementation in the base class. The question regarding case 2 is how to both 1. override protected vritual MemberName and 2. expose a public member called MemberName. It sounds like it is impossible without replacing the single subclass with two subclasses to incrementally override and then new.Hazelhazelnut
@Hazelhazelnut I don't follow you at all. Where did I say that protected members and overriding them is not useful? The OP asked why when overriding such methods you are not allowed to change the access modifier, and my answer addresses exactly that concern: overriding a protected method and changing its access modifier helps you in exactly what? And how is it any better than new?Hoodoo
@InBetween, The text between the quotes was verbatim from your answer. Sometimes new is not sufficient. If you need your subclass to both override some behavior in the base class and want to use the same identifier as part of your subclass’s public interface, then override is necessary (and using override prevents you from using new). See my answer where I demonstrate how to both override and new a member…Hazelhazelnut
@Hazelhazelnut My question remains: what is the benefit of overriding a protected method and making it public? The public API of the base class is what it is, you can't change that, you have no right to; making said method public in a derived class will not change the accessibility of the method in the base class so you can't take advantage of the virtual call to begin with. That is why new essentially serves the purpose already; BaseClass.ProtectedChangedToPublicOverridenMethod is not a valid call because ProtectedChangedToPublicOverridenMethod is not part of the public API of BaseClassHoodoo
@Hazelhazelnut and the quoted text does not say what you imply it says. Overriding and changing the access modifier has no practical benefits. Overriding by itself obviously does.Hoodoo
@Hazelhazelnut And last but not least, your answer is just a workaround to the problem; you are essentially changing the access modifier by using new by the way. The OP is not asking for a workaround, he's asking why the language doesn't allow what he pretends and my reasoning remains valid. Your example does not prove anything different.Hoodoo
@InBetween, the benefit of being able to both override and new is that sometimes you need to both override a protected member and expose a public property of the same name and behavior. Using override might change the behavior exhibited by the base class's public members. And say you're implementing an interface that requires a member of the same name and you prefer to implement it implicitly rather than explicitly at the same time. Or you're using binding or serialization based on public members of the subclass. I guess I'm arguing that there's no reason for the restriction.Hazelhazelnut
@Hazelhazelnut I'm sorry but I still fail to see your point. First: Why would it ever be necessary to publicly expose an overriden protected member with the same name? What prevents you from simply creating a new member with an adequate name that delegates implementation to the overriden member? Second: Explicitly implemented interfaces are in the language for a reason; requesting a dubious new feature just because you don't like using them seems a pretty thin argument.Hoodoo
@Hoodoo re first “with same name”: there are cases when creating a public property with a specific name is required, such as when creating something which is meant to serialize a certain way or be visible to someone doing .GetMethod("ParticularName") such as winforms binding. re second “explicitly implemented interfaces are in the language for a reason”: explicitly interfaces are oftentimes unnecessarily verbose, cannot directly participate in virtual overrides, are not visible to sub classes reimplementing the same interface, and cannot be automatically generated properties.Hazelhazelnut
I think all I’m trying to say is that making a property more visible (e.g., making a protected base class member public in a sub class) is not pointless. You start your answer by saying that what the OP wants (making a base class’s protected thing public) is pointless. However, sometimes that’s the exact reason one is making the sub class in the first place!Hazelhazelnut
@Hazelhazelnut again, what does overriding a member changing its accessibility from protected to public achieve that you can’t already do with regular vorrrdong and new?Hoodoo
@Hoodoo it would allow you to skip the intermediate base class, reducing the amount of code and thus reducing chance of programmer error and increasing readability.Hazelhazelnut
@Hazelhazelnut what intermediate base class? I’m not following you a all. Changing a virtual members accessibility from protected to public could only be leveraged from the class where it’s overriden, you’d never be able to call it from a base class typed variable because the method is not public in the base class therefore polymorphism goes down the drain. If your going to call it only from a derived typed variable, new is enough.Hoodoo
@Hoodoo You can use a workaround to get a class which has a public member of the same name as the overridden one and still override the base class’s member. It requires an intermediate base class. It’s the same strategy used to override a virtual/abstract get-only property with a get/set property. You’d be able to call it from a base class-typed variable if that base type makes the method accessible by proxying calls to it. It doesn’t break polymorphism—it can still be used as the base typeHazelhazelnut
@Binki Your missing the point. Whats that pattern good for? You still can't call base.Foo() outside Foo or derived types, so what are the benefits? If your only going to call derived.Foo() why the whole fuzz to begin with? Just implement a new and be done with it.Hoodoo
@Hazelhazelnut And in the rare cases where this might be useful (I still have to find a case where the name of a protected member conflicted with a required public member in a derived type that couldn't be solved otherwise) you have already shown that the language has sufficient mechanisms to solve the problem. You are proposing making a first class language feature that solves an extremely rare corner case.Hoodoo
L
12

OK, I found a small note from Eric Lippert in the Annotated C# reference:

An overridden virtual method is still considered to be a method of the class that introduced it. The overload resolution rules in some cases prefer members of more derived types ... overriding a method does not "move" where that method belongs in this hierarchy.

So this is an intentional rule to prevent the 'brittle base class' problem and provide better versioning, ie less problems when a base class changes.

But note that it has nothing to do with security, type-safety or object-state.

Levigate answered 4/6, 2011 at 13:49 Comment(4)
I think it just has to do without it being pointless. see my answer for reasoning.Hoodoo
I can't make sense out that 1st part of your sentence.Levigate
sorry cell phone autocomplete...What I meant to say is that I find the ability to change access when overriding pointless.Hoodoo
So you're saying that the compiler error you get in a subclass when the visibility of a base class's member changes avoids the brittle base class problem by forcing the developer to review the subclass at that point. That does actually sound useful.Hazelhazelnut
C
3

If you change visibility modifiers from a more restrictive modifier to a less restrictive modifier you allow class clients access to methods designated for internal use. Essentially you've provided a means to alter class state that may not be safe.

Carce answered 4/6, 2011 at 13:12 Comment(5)
class Derived { public string foo2() { return foo(); } } so I don't think your argument is enough.Levigate
@Henk : That face that you can circumvent class visibility modifiers doesn't change the fact that you are allowing access to methods designated for internal use that may cause problems. It may be that case that no problems would arise, or stuff may blow up. If you find that wrapping a non-public member to make it publicly accessible doesn't cause problem, the class design is probably wrong. This doesn't mean that circumventing visibility modifiers is a good idea.Carce
I'm expecting an answer in terms of interfaces and substitution. A derived class can always add to the public interface, it cannot reduce it. And the argument about object-state simply does not hold.Levigate
@Henk : Of course a derived class can add to the interface, but that wasn't the question. The question was why changing an existing method's visibility to a more permissive level via overriding is not allowed. The question was not concerned with wrapping or use of a non-public method. Overriding, as shown in the question, will not prevent class substitution, nor will a dding an additional public methods (unless clients check method meta-data).Carce
I think it was the question. But see my answer about 'brittle base class'.Levigate
H
2

Reducing visibility is impossible because if Base.Member was visible and Derived.Member was not visible, that would break the whole “Derived is a Base” concept in OOP. However, increasing visibility is disallowed maybe because the language developers think that changing the visibility would be a mistake most of the time. However, you can always use the new keyword to hide base class members by introducing a member with the same name but a different behavior. This new member belongs to the derived type’s interface, so of course you can still access the base type’s interface by casting to that base type. Depending on how you write your subclass, your new member might effectively increase the visibility of the base class’s property—but remember that the base class’s property can still be accessed directly (e.g., a subclass of your subclass could cast this to Base and bypass your property).

The question here is how to both override and new the same named member (identifier) in a subclass. That is apparently not possible. At the very least, I can say through experimentation that public new override string foo(){return "";} is not a syntax for that. However, you can get the same effect by using two subclasses:

using System;
class Base
{
    protected virtual string foo()
    {
        return "Base";
    }
    public void ExhibitSubclassDependentBehavior()
    {
        Console.WriteLine("Hi, I am {0} and {1}.", GetType(), foo());
    }
}

abstract class AbstractDerived : Base
{
    protected virtual string AbstractFoo()
    {
        return base.foo();
    }
    protected override string foo()
    {
        return AbstractFoo();
    }
}

class Derived : AbstractDerived
{
    protected override string AbstractFoo()
    {
        return "Deprived";
    }
    public new string foo()
    {
        return AbstractFoo();
    }
}

static class Program
{
    public static void Main(string[] args)
    {
        var b = new Base();
        var d = new Derived();
        Base derivedAsBase = d;
        Console.Write(nameof(b) + " -> "); b.ExhibitSubclassDependentBehavior(); // "b -> Hi, I am Base and Base."
        Console.WriteLine(nameof(d) + " -> " + d.foo()); // "d -> Deprived"
        Console.Write(nameof(derivedAsBase) + " -> "); derivedAsBase.ExhibitSubclassDependentBehavior(); // "derivedAsBase -> Hi, I am Derived and Deprived."
    }
}

The intermediate subclass (AbstractDerived) uses override and introduces a new, differently-named member that the subclass and sub-subclasses can continue to override the base class’s member as they see fit. The sub-subclass (Derived) uses new to introduce the new API. Since you can only use new or override with a particular identifier only once per level of subclassing, you need two levels of subclassing to effectively use both on the same identifier.

So, in a way, you can change the visibility while overriding methods—it’s just a pain and there’s no syntax I know of to accomplish it with just one level of inheritance. However, you might have to use some trick like this depending on what interfaces you’re trying to implement and what your base class looks like. I.e., this may or may not be what you actually want to do. But I still wonder why C# does not just support this to begin with. IOW, this “answer” is just a re-expression of the OP’s question with a workaround ;-).

Hazelhazelnut answered 20/3, 2015 at 18:35 Comment(0)
U
1

You can make derived class's access less than the base's, but not more. Otherwise it would contradict base's definition and expose its components beyond what was intended.

Updraft answered 4/6, 2011 at 13:11 Comment(2)
No, you cannot change the acces at all when overriding. And how would it contradict the base class in any way? A derived class always has its own interface.Levigate
if you could restrict access you would be modifying the interface.Hoodoo
M
0

Reasons are obvious. Security and Integrity of the objects.

In this particular example, what if external entities start modifying the property of the object which is protected according the base-class. Things will go haywire. What about the client-code that is written against the base-class to which all/any derived class must conform to.

Mm answered 4/6, 2011 at 13:10 Comment(2)
It has nothing to do with security. And code expecting the base class simply would not see the public derived method.Levigate
Changing access of overriden methods is just pointless because it doesnt add any benefits to the language (increasing access) or its not allowed because you would break the base class contract (limiting access). It has nothing to do with security. See my answer for reasoning.Hoodoo
S
0

if it had different access modifiers you can't really consider it the same method any more. kind of suggests a problem with the design of the model.

a better question would be why would you want to change the access modifiers?

Sanhedrin answered 4/6, 2011 at 13:15 Comment(0)
H
0

Overriding is a term which enables you to change or augment the behavior of methods in a base class. Overriding gives you the control to write new logic for an existing method.

Changing the method signature of a base class is somewhat like writing a new method instead of overriding the existing one. It contradicts the purpose of overriding a method. So maybe the reason why you cannot change the access modifier while overriding methods in C#.

Halpern answered 10/5, 2018 at 11:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.