Why Can't I Access C# Protected Members Except Like This

Why can't I access C# protected members except like this?

The "protected" keyword means that only a type and types that derive from that type can access the member. D has no relationship to C therefore cannot access the member.

You have a couple of options if you want to be able to access that member

  • Make it public
  • Make it internal. This will allow any types to access the member within the same assembly (or other assemblies should you add friend's)
  • Derive D from C

EDIT

This scenario is called out in section 3.5.3 of the C# spec.

The reason this is not allowed is because it would allow for cross hierarchy calls. Imagine that in addition to D, there was another base class of C called E. If your code could compile it would allow D to access the member E.F. This type of scenario is not allowed in C# (and I believe the CLR but I don't 100% know).

EDIT2 Why this is bad

Caveat, this is my opinion

The reason this is now allowed is it makes it very difficult to reason about the behavior of a class. The goal of access modifiers is to give the developer control over exactly who can access specific methods. Imagine the following class

sealed class MyClass : C {
override F(D d) { ... }
}

Consider what happens if F is a somewhat time critical function. With the current behavior I can reason about the correctness of my class. After all there are only two cases where MyClass.F will be called.

  1. Where it's invoked in C
  2. Where I explicitly invoke it in MyClass

I can examine these calls and come to a reasonable conclusion about how MyClass functions.

Now, if C# does allow cross hierarchy protected access I can make no such guarantee. Anyone in a completely different assembly can come by and derive from C. Then they can call MyClass.F at will. This makes it completely impossible to reason about the correctness of my class.

Can't access protected member of the same base class

From the C# 5 spec, section 3.5.3:

When a protected instance member is accessed outside the program text of the class in which it is declared, and when a protected internal instance member is accessed outside the program text of the program in which it is declared, the access must take place within a class declaration that derives from the class in which it is declared. Furthermore, the access is required to take place through an instance of that derived class type or a class type constructed from it. This restriction prevents one derived class from accessing protected members of other derived classes, even when the members are inherited from the same base class.

So you're fine to access the Parent property of any NodeDerived object:

NodeDerived derivedNode = ...;
Node parent = derivedNode.Parent;

... but you can't access the Parent property for a node type which isn't NodeDerived or a subclass.

Using this.Parent works because the compile-time type of this is NodeDerived.

I suspect you'll want to make your Parent property public - assuming that you want this code to work with nodes other than NodeDerived.

Cannot access protected members from a derived class

It's exactly as you said. parentInstance could be an instance of ChildClass2, so exposing that object's protected members to your ChildClass would create a possible security threat.

Imagine the following scenario:

You have an extensible class A, which exposes some protected members to its derived classes (which might, for example, mutate protected state or call other, possibly virtual members) and a derived class B, which uses the base functionality to do some security critical stuff, while exposing only a safe API with all kinds of error and permission checking.

Now, would you really want anyone to be able to easily bypass those checks by simply deriving a class C from A which then could directly call the protected methods on an object of type B?

Protected member not accessible in a derived class?

If O, A and B are all in the same assembly, you could use internal if you don't want it to be public. Otherwise you are limited to public access in this case.

When you try to access a base class member in this way, you are accessing it via the public API only, not via protected. You can see this for yourself by trying the following:

public sealed class B : O
{
public B(string val, O instance)
: base(val)
{
instanceO = instance;
instanceO.ValueChanged += MyMethod;
}

private O instanceO;
}

This still gives a compilation error. You can access ValueChanged in B, but only via an instance of B, as it says in the quote:

The protected keyword is a member access modifier. A protected member is accessible within its class and by derived class instances

(emphasis mine).

Cannot access protected member?

From protected (C# Reference)

The protected keyword is a member access modifier. A protected member
is accessible within its class and by derived class instances.

So from this comment, it is accessible from within ProtectedDemo or from the inheriting class Demo

And then their example

class A
{
protected int x = 123;
}

class B : A
{
static void Main()
{
A a = new A();
B b = new B();

// Error CS1540, because x can only be accessed by
// classes derived from A.
// a.x = 10;

// OK, because this class derives from A.
b.x = 10;
}
}

So change you class to

class Demo : ProtectedDemo
{
static void Main(string[] args)
{
//ProtectedDemo p = new ProtectedDemo();
Demo p = new Demo(); //NOTE HERE
Console.Write("Enter your Name:");
p.name = Console.ReadLine(); //Here i am getting the error.
p.Print();
Console.ReadLine();
}
}

Why can't I have protected interface members?

I think everyone hammered the point of an interface having only public members, no implementation details. What you are looking for is an abstract class.

public interface IOrange
{
OrangePeel Peel { get; }
}

public abstract class OrangeBase : IOrange
{
protected OrangeBase() {}
protected abstract OrangePips Seeds { get; }
public abstract OrangePeel Peel { get; }
}

public class NavelOrange : OrangeBase
{
public override OrangePeel Peel { get { return new OrangePeel(); } }
protected override OrangePips Seeds { get { return null; } }
}

public class ValenciaOrange : OrangeBase
{
public override OrangePeel Peel { get { return new OrangePeel(); } }
protected override OrangePips Seeds { get { return new OrangePips(6); } }
}

Edit: It is fair to argue that if we have a PlasticOrange that derives from a class Ornament, it can only implement IOrange and not the Seeds protected method. That is fine. An interface by definition is a contract between a caller and an object, not between a class and its subclasses. The abstract class is as close as we come to this concept. And that is fine. What you are essentially proposing is another construct in the language through which we can switch subclasses from one base class to another without breaking the build. To me, this doesn't make sense.

If you are creating a subclass of a class, the subclass is a specialization of the base class. It should be fully aware of any protected members of the base class. But if you suddenly want to switch the base class out, it makes no sense that the subclass should work with any other IOrange.

I suppose you have a fair question, but it seems like a corner case and I don't see any benefit from it to be honest.

Cannot access protected member in base class

Why does this happen?

An answer that cannot be argued with is "because the spec says so":

A protected member of a base class is accessible in a derived class
only if the access occurs through the derived class type.

But let's explore this restriction behind the scenes.

Explanation

What happens here is the same thing that Eric Lippert describes in the blog post that you linked to. Your code does the equivalent of this:

public abstract class MenuItem
{
protected string m_Title;
}

public class ContainerItem : MenuItem
{
void Foo()
{
var derivedItem = new ContainerItem();
derivedItem.m_Title = "test"; // works fine

var baseItem = (MenuItem)derived;
baseItem.m_Title = "test"; // compiler error!
}
}

The problem here stems from the fact that this might happen. For the moment, please disregard the fact that this example uses a method instead of a field -- we 'll come back to it.

public abstract class MenuItem
{
protected void Foo() {}
}

public class SomeTypeOfItem : MenuItem
{
protected override void Foo() {}
}

public class ContainerItem : MenuItem
{
void Bar()
{
var baseItem = (MenuItem)something;
baseItem.Foo(); // #1
}
}

Look at line #1: how does the compiler know that baseItem is not actually a SomeTypeOfItem? If it is, you certainly must not be able to access Foo! So, as Eric describes, the compiler is unable to statically prove that the access is always legal and because of that it has to disallow this code.

Note that in some cases, for example if

baseItem = (MenuItem)new ContainerItem();

or even

baseItem = (MenuItem)this;

the compiler does have enough information to prove that the access is legal but it still will not allow the code to compile. I imagine that's because the compiler team is not convinced that implementing such special-case handlers is worth the trouble (a point of view which I am sympathetic to).

But... but...

That's all well and good for methods (and properties, which are really methods) -- what about fields? What about this:

public abstract class MenuItem
{
protected string m_Title;
}

public class SomeTypeOfItem : MenuItem
{
protected new string m_Title;
}

public class ContainerItem : MenuItem
{
void Foo()
{
var baseItem = (MenuItem)something;
baseItem.m_Title = "Should I be allowed to change this?"; // #1
}
}

Since fields cannot be overridden, there should be no ambiguity here and the code should compile and set MenuItem.m_Title irrespective of what the type of something is.

Indeed, I cannot think of a technical reason why the compiler couldn't do this, but there is a good reason in any case: consistency. Eric himself would probably be able to provide a richer explanation.

So what can I do?

How would you access the protected members like m_Title while holding
a reference to MenuItem (because of Polymorphism design reasons)?

You simply cannot do that; you would have to make the members internal (or public).

What's the real reason for preventing protected member access through a base/sibling class?

UPDATE: This question was the subject of my blog in January 2010. Thanks for the great question! See:

https://blogs.msdn.microsoft.com/ericlippert/2010/01/14/why-cant-i-access-a-protected-member-from-a-derived-class-part-six/


Does anyone have an example of a
problem that would be caused by
letting MyDerived access Base's
protected members through a variable
of type YourDerived or Base, but does
not exist already when accessing them
through a variable of type MyDerived
or MySuperDerived?

I am rather confused by your question but I am willing to give it a shot.

If I understand it correctly, your question is in two parts. First, what attack mitigation justifies the restriction on calling protected methods through a less-derived type? Second, why does the same justification not motivate preventing calls to protected methods on equally-derived or more-derived types?

The first part is straightforward:

// Good.dll:

public abstract class BankAccount
{
abstract protected void DoTransfer(BankAccount destinationAccount, User authorizedUser, decimal amount);
}

public abstract class SecureBankAccount : BankAccount
{
protected readonly int accountNumber;
public SecureBankAccount(int accountNumber)
{
this.accountNumber = accountNumber;
}
public void Transfer(BankAccount destinationAccount, User user, decimal amount)
{
if (!Authorized(user, accountNumber)) throw something;
this.DoTransfer(destinationAccount, user, amount);
}
}

public sealed class SwissBankAccount : SecureBankAccount
{
public SwissBankAccount(int accountNumber) : base(accountNumber) {}
override protected void DoTransfer(BankAccount destinationAccount, User authorizedUser, decimal amount)
{
// Code to transfer money from a Swiss bank account here.
// This code can assume that authorizedUser is authorized.

// We are guaranteed this because SwissBankAccount is sealed, and
// all callers must go through public version of Transfer from base
// class SecureBankAccount.
}
}

// Evil.exe:

class HostileBankAccount : BankAccount
{
override protected void Transfer(BankAccount destinationAccount, User authorizedUser, decimal amount) { }

public static void Main()
{
User drEvil = new User("Dr. Evil");
BankAccount yours = new SwissBankAccount(1234567);
BankAccount mine = new SwissBankAccount(66666666);
yours.DoTransfer(mine, drEvil, 1000000.00m); // compilation error
// You don't have the right to access the protected member of
// SwissBankAccount just because you are in a
// type derived from BankAccount.
}
}

Dr. Evil's attempt to steal ONE... MILLION... DOLLARS... from your swiss bank account has been foiled by the C# compiler.

Obviously this is a silly example, and obviously, fully-trusted code could do anything it wants to your types -- fully-trusted code can start up a debugger and change the code as its running. Full trust means full trust. Don't actually design a real security system this way!

But my point is simply that the "attack" that is foiled here is someone attempting to do an end-run around the invariants set up by SecureBankAccount, to access the code in SwissBankAccount directly.

That answers your first question, I hope. If that's not clear, let me know.

Your second question is "Why doesn't SecureBankAccount also have this restriction?" In my example, SecureBankAccount says:

    this.DoTransfer(destinationAccount, user, amount);

Clearly "this" is of type SecureBankAccount or something more derived. It could be any value of a more derived type, including a new SwissBankAccount. Couldn't SecureBankAccount be doing an end-run around SwissBankAccount's invariants?

Yes, absolutely! And because of that, the authors of SwissBankAccount are required to understand everything that their base class does! You can't just go deriving from some class willy-nilly and hope for the best! The implementation of your base class is allowed to call the set of protected methods exposed by the base class. If you want to derive from it then you are required to read the documentation for that class, or the code, and understand under what circumstances your protected methods will be called, and write your code accordingly. Derivation is a way of sharing implementation details; if you don't understand the implementation details of the thing you are deriving from then don't derive from it.

And besides, the base class is always written before the derived class. The base class isn't up and changing on you, and presumably you trust the author of the class to not attempt to break you sneakily with a future version. (Of course, a change to a base class can always cause problems; this is yet another version of the brittle base class problem.)

The difference between the two cases is that when you derive from a base class, you have the behaviour of one class of your choice to understand and trust. That is a tractable amount of work. The authors of SwissBankAccount are required to precisely understand what SecureBankAccount guarantees to be invariant before the protected method is called. But they should not have to understand and trust every possible behaviour of every possible cousin class that just happens to be derived from the same base class. Those guys could be implemented by anyone and do anything. You would have no ability whatsoever to understand any of their pre-call invariants, and therefore you would have no ability to successfully write a working protected method. Therefore, we save you that bother and disallow that scenario.

And besides, we have to allow you to call protected methods on receievers of potentially more-derived classes. Suppose we didn't allow that and deduce something absurd. Under what circumstances could a protected method ever be called, if we disallowed calling protected methods on receivers of potentially-more-derived classes? The only time you could ever call a protected method in that world is if you were calling your own protected method from a sealed class! Effectively, protected methods could almost never be called, and the implementation that was called would always be the most derived one. What's the point of "protected" in that case? Your "protected" means the same thing as "private, and can only be called from a sealed class". That would make them rather less useful.

So, the short answer to both your questions is "because if we didn't do that, it would be impossible to use protected methods at all." We restrict calls through less-derivedtypes because if we don't, it's impossible to safely implement any protected method that depends on an invariant. We allow calls through potential subtypes because if we do not allow this, then we don't allow hardly any calls at all.

Does that answer your questions?

C# accessing protected member in derived class

You're not accessing it from inside the class, you're trying to access the variable as though it were public. You would not expect this to compile, and this is pretty much what you are trying to do:

public class SomethingElse
{
public void CallHowdy()
{
A a = new A();
Console.WriteLine(a.Howdy);
}
}

There is no relationship, and it sounds like you are confused why that field is not public.

Now, you could do this, if you wanted to:

public class B : A
{
public void CallHowdy()
{
Console.Writeline(Howdy);
}
}

Because B has inherited the data from A in this instance.

Not able to access protected variables

You are misunderstanding the purpose of inheritance. Inheritance is designed to represent a relationship between two objects where one is a more specialized version of the other. This is sometimes called an "is-a" relationship.

Consider the following class definitions:

class Fruit {}
class Apple : Fruit {}
class Banana: Fruit {}

In this case, Apple and Banana both inherit from Fruit to express the "is-a" relationship - a Banana is a Fruit. In object-oriented design, this allows you to write a method like this:

class Person
{
public void Eat(Fruit fruit) {}
{
// stuff goes here
}
}

The Eat method allows the Person class to eat anything that is a Fruit, including classes that derive from Fruit. So you can do the following:

Person person = new Person();
Apple apple = new Apple();
Banana banana = new Banana();

person.Eat(apple);
person.Eat(banana);

Compare this to the class definition you have written:

class Program : CustomerInfo

In the language of OOP, this says "a Program is a CustomerInfo." I don't think that's what you want. Using the protected keyword doesn't make sense here because your inheritance relationship doesn't make sense. If Program is supposed to be able to access CustomerInfo members, they should be declared public or internal.



Related Topics



Leave a reply



Submit