This code:
abstract class C { protected abstract void F(D d); } class D : C { protected override void F(D d) { } void G(C c) { c.F(this); } }
Generates this error:
Cannot access protected member ‘C.F(D)’ via a qualifier of type ‘C’; the qualifier must be of type ‘D’ (or derived from it)
What in the world were they thinking? (Would altering that rule break something?) And is there a way around that aside from making F public?
Edit: I now get the reason for why this is (Thanks Greg) but I’m still a bit perplexed as to the rational; given:
class E : C { protected override void F(D d) { } }
Why shouldn’t D be able to be able to call E.F?
The error message is edited so I might have put a typo in there.
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
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
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.
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.