6

As explained in this question, and these articles, the following is not allowed:

public class A
{
    protected virtual int X {get; private set;}
}

public class B : A
{
    public int Add(A other)
    {
        return X + other.X;
    }
}

Because if it was, and you had this:

public class C : A 
{  
    protected override int X { get { return 4; } }
}

and then:

A c = new C();
B b = new B();
b.Add(c);

This is illegal because even though B's access to X means it knows that C has the desired signature it's still not allowed to actually access the member.


So far, so good. But given the above, what I'm confused about is why I can do this:

public class A
{
    protected virtual int X { get; private set; }

    public int Add(A other)
    {
        return X + other.X;
    }
}

And, therefore, this:

A c = new C();
A a = new A();
a.Add(c);

The definition of the protected keyword says:

A protected member is accessible within its class and by derived class instances.

But now the protected member on C is being accessed from within A, which is neither "its class" nor a "derived class instance", but a parent class. While A obviously has access to the signature, the sibling example seems to indicate that that alone is not supposed to be sufficent, so why is protected granting it access to the member?

Community
  • 1
  • 1
Ben Aaronson
  • 6,955
  • 2
  • 23
  • 38
  • Maybe I'm just being dense (wouldn't be the first time), but I don't see your definition for class "C". You've only posted code that illustrates what C *cannot* be by virtue of the rules, so I'm not able to see your illustration about the behavior of "C." – David W May 01 '15 at 14:00
  • `A` is 'the class' for `X`, and it's not clear what distinction you are trying to draw between the declaration of `X` and the 'signature'. – Lee May 01 '15 at 14:01
  • In the second example, your `Add` method is declared inside of `A` and so you're accessing the `protected` member `A.X` inside of the declaring class, which is allowed under the definition of `protected` – Andrew Whitaker May 01 '15 at 14:04
  • @DavidW `C` is as defined. `C` is legal, it's `other.X` in `B.Add` which isn't, and `C` is used as part of an example of what you could do if `other.X` was. – Ben Aaronson May 01 '15 at 14:04
  • @Lee Surely "the class" in that sentence must refer to the actual runtime class `C`, not the static class `A`, otherwise why would the first example be illegal? The distinction I'm trying to draw is that `B` "knows" that `C` has an `int X` property, it just isn't allowed to call it. – Ben Aaronson May 01 '15 at 14:06

2 Answers2

5

This is defined by the specification:

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 is required to take place through an instance of the derived class type in which the access occurs.:

public class A
{
   protected int x;
   static void F(A a, B b)
   {
      a.x = 1;      // Ok
      b.x = 1;      // Ok
   }
}

public class B : A
{
   static void F(A a, B b) 
   {
      a.x = 1;      // Error, must access through instance of B
      b.x = 1;      // Ok
   }
}

within A, it is possible to access x through instances of both A and B, since in either case the access takes place through an instance of A or a class derived from A. However, within B, it is not possible to access x through an instance of A, since A does not derive from B.

The entire point of this being the fact that I wouldn't want anyone of class C, although allowed to derive from my class A, access my "internal" state in class B, although both of them share the fact that they are derivatives of class A.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • I don't see that quote on the page you linked – Ben Aaronson May 01 '15 at 14:10
  • @BenAaronson - that page does link off to the specification. For some unfathomable reason, beyond .NET 1.1, they decided to only put the specs into word documents that you have to download (or install with VS) rather than having them available on the web. – Damien_The_Unbeliever May 01 '15 at 14:12
  • @BenAaronson I Accidentally linked to the wrong link. Fixed. – Yuval Itzchakov May 01 '15 at 14:18
  • @YuvalItzchakov Okay, thanks! Well it's good to know it's documented, but this seems to be more a statement of the question rather than an explanation. I'll leave it open a while to see if I get any reasoning to why it's like this (which I know can often be a tricky prospect to answer). If not I'll accept this – Ben Aaronson May 01 '15 at 14:20
  • @BenAaronson I added an explanation to why that isn't possible. – Yuval Itzchakov May 01 '15 at 14:37
4

As the author of C, I get to choose my base class. So I've found A, I've read its documentation, I know how and why it will invoke any of my inherited protected members (and, of course, I have options such as sealed or protecting my constructors to control which classes, if any, can derive from my C). That's all I really have to think about (outside of reflection/full control scenarios, but once reflection is in the picture all bets are off).

What I don't have to worry about is someone else deciding they want to invoke those protected methods. Which (under your proposed modification), they'd be able to do by simply creating their own class, B, derived from A.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
  • Not a proposed modification! Just an example for contrast. I guess this answer fits well with Eric Lippert's description here: http://blogs.msdn.com/b/ericlippert/archive/2010/01/14/why-cant-i-access-a-protected-member-from-a-derived-class-part-six.aspx – Ben Aaronson May 01 '15 at 14:23
  • Really nice way of explaining the situation. Super. – David W May 01 '15 at 14:24
  • 1
    @BenAaronson - yes, I know you weren't necessarily looking for/asking for things to change. I was just trying to find some shorthand for "if the rules weren't the way they are and the code in your first example did compile" – Damien_The_Unbeliever May 01 '15 at 14:27