Why does initialising a derived class variable and assigning to its base class type not allow access to its members?

I have started learning C# and object oriented programming and I must admit it's really fun. Now, as I was learning about inheritance and polymorphism, the following thought crossed my mind and I tried to make it work in code and see the results. I'll post the code and then ask specific questions so that it'll be easier for anyone answering to follow the train of thought that I had.

class Program
{
    public static void Main(string[] args)
    {
        B b = new B();
        b.b = 5;
        A a = b;
        Console.WriteLine(a.b);
    }
}

class A
{
}

class B : A
{
    public int b;
}

Now, when I try and run the above code, it gives me a compile time error saying "'ConsoleApplication1.A' does not contain a definition for 'b' and no extension method 'b' accepting a first argument of type 'ConsoleApplication1.A' could be found". Essentially what I understand this means is that the member variable b is not accessible.

However, if I comment out the Console.WriteLine() and execute in Debug mode and hover over the a variable declared as 'A' class type, the object it points to does have a member variable b with the value of 5.

My question is -

  • Why isn't the member variable accessible for the a variable of class type A? (I'll admit I sort of understand that at compile time the compiler doesn't know that the object being assigned to the variable 'a' has the member variable b which is assigned the value 5, which brings me to my next question)
  • Is this some sort of inherent flaw in the concept of inheritance that although objects of the base class have members of the derived class, they cannot be accessed because they are assigned to variables of base class type?
Jon Skeet
people
quotationmark

Your self-answer in the first bullet point is correct: the compiler doesn't look at what values have been assigned to a variable when working out what members are available. It only cares about the compile-time type of the variable. It's not about whether the b variable is "accessible" in the normal sense (public, private, internal etc) - it's about whether the member is even considered to exist as far as the compiler is concerned. You're using an expression of type A, so when the compiler tries to resolve member b, it simply doesn't find it.

As for your second bullet point: no, I don't see that as an inherent flaw at all. Arguably it's a benefit, in that it makes you think about the level of abstraction you're trying to work at. That in turns allows you to replace one implementation of that abstraction with another. If you could always (somehow) access the derived type's members, then if you later wanted to replace the value with an instance of a different derived type, your code could break. If you want to depend on the value of a being a B reference, then simply declare the variable as being of type B rather than A. By declaring the variable using type A, you're explicitly saying "I don't care what the implementation is; I only care about using this object from the perspective of it being an A."

There's one way round this in C# though: using dynamic instead. That way, all member access is resolved at execution time instead of compile time, and acts on the execution-time type of the dynamically-typed variable. (Or rather, whatever view of that you would normally have access to, following the normal access control rules.)

For example:

B b = new B();
b.b = 5;
dynamic a = b;
Console.WriteLine(a.b);

That will compile and run. Of course, it's not very safe, because you could equally have:

Console.WriteLine(a.typoInMemberName);

... which will still compile, but fail at execution time. This is one downside of using dynamic typing.

people

See more on this question at Stackoverflow