I’m setting up some demo code for a beginner session on accessibility and I found that I am able to access an internal protected property from a derived class. What am I missing?
Assembly 1
namespace Accessibility
{
class Program
{
static void Main(string[] args)
{
ExampleClass c = new ExampleClass();
c.Go();
//c.Prop1 = 10;
}
}
class ExampleClass : DerivedClass
{
public void Go()
{
this.Prop1 = 10;
this.Prop2 = 10;
//this.Prop3 = 10; //Doesn't work
//this.Prop4 = 10; //Doesn't work
this.Prop5 = 10; //why does this work?!
this.DoSomething();
}
}
}
Assembly 2
namespace Accessibility.Models
{
public class BaseClass
{
public int Prop1 { get; set; }
protected int Prop2 { get; set; }
private int Prop3 { get; set; }
internal int Prop4 { get; set; }
internal protected int Prop5 { get; set; }
//internal public int Prop6 { get; set; } //Invalid
//internal private int Prop7 { get; set; } //Invalid
public BaseClass()
{
this.Prop3 = 27;
}
}
public class DerivedClass : BaseClass
{
public void DoSomething()
{
this.Prop1 = 10;
this.Prop2 = 10;
//this.Prop3 = 10; //Doesn't work
this.Prop4 = 10;
this.Prop5 = 10;
PropertyInfo Prop3pi = typeof(DerivedClass).GetProperty("Prop3", BindingFlags.Instance | BindingFlags.NonPublic);
int value = (int)Prop3pi.GetValue(this, null);
}
}
}
Notice in ExampleClass.Go I can set a value to Prop5. Why? It’s marked as internal protected but I can’t set a value on Prop4 (marked as internal)
internal protectedmeans “internal to the assembly OR an inherited class”. So yes, if you have a public class with an protected internal member, another class that inherits that type in a different assembly can still access it because of the protected modifier:Reference: http://msdn.microsoft.com/en-us/library/ms173121.aspx
This is a limitation of the C# language. The CLR supports the “Internal AND Protected” notion. There is evidence of this with the
MethodAttributes.FamANDAssemenumeration if you were emitting your own IL. If you really wanted this feature, you could do some IL post processing with something like Mono.Cecil. Why the C# language does not expose this is only a guess: little need for it.