Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# protected field access [duplicate]

(This question is a follow-up to C# accessing protected member in derived class)

I have the following code snippet:

public class Fox
{
    protected string FurColor;
    private string furType;

    public void PaintFox(Fox anotherFox)
    {
        anotherFox.FurColor = "Hey!";
        anotherFox.furType = "Hey!";
    }
}

public class RedFox : Fox
{
    public void IncorrectPaintFox(Fox anotherFox)
    {
        // This one is inaccessible here and results in a compilation error.
        anotherFox.FurColor = "Hey!";
    }

    public void CorrectPaintFox(RedFox anotherFox)
    {
        // This is perfectly valid.
        anotherFox.FurColor = "Hey!";
    }
}
  • Now, we know that private and protected fields are private and protected for type, not instance.

  • We also know that access modifiers should work at compile time.

  • So, here is the question - why can't I access the FurColor field of the Fox class instance in RedFox? RedFox is derived from Fox, so the compiler knows it has access to the corresponding protected fields.

  • Also, as you can see in CorrectPaintFox, I can access the protected field of the RedFox class instance. So, why can't I expect the same from the Fox class instance?

like image 633
Yippie-Ki-Yay Avatar asked May 18 '12 20:05

Yippie-Ki-Yay


2 Answers

Simple reason is:

public void IncorrectPaintFox(Fox anotherFox)
{
    anotherFox = new BlueFox();

    // This one is inaccessible here and results in a compilation error.
    anotherFox.FurColor = "Hey!";
}

Now you're not accessing the protected field from within BlueFox, therefore since the compiler doesn't know what the runtime type is, it has to always make this an error.

like image 193
Tod Hoven Avatar answered Oct 25 '22 02:10

Tod Hoven


To expand slightly on the accepted answer, the reason the compiler enforces this rule, as opposed to the much more lax meaning of protected that PHP has, is because allowing the access you want to allow would make it possible to break the invariants of a class, by bypassing its defined protection levels. (Of course, this is always possible e.g. via Reflection, but the compiler at least makes it hard to do by accident).

The problem is that just knowing that some object is a Fox does not make it safe for you to interact with its internal workings, because it may not actually be a Fox at runtime. Consider these classes:

public class Fox
{
  protected Color FurColor;
}

public class RedFox
{
  public RedFox () 
  { 
    this.FurColor = Color.Red; 
  }
}

public class ArcticFox
{
  public ArcticFox () 
  { 
    this.FurColor = Color.White; 
  }
}  

What you are asking is for the compiler to permit the following method, assuming it was defined on the RedFox class:

public void PaintFoxRed ( Fox fox )
{
    fox.FurColor = Color.Red;
}

But if that were legal, I could do this:

RedFox a = new RedFox();
Fox b = new ArcticFox();
a.PaintFoxRed(b);

My ArcticFox is now red despite the class itself only allowing itself to be white.

like image 43
Michael Edenfield Avatar answered Oct 25 '22 00:10

Michael Edenfield