Tim
Tim

Reputation: 1344

C# type conversion returning child class when specifying type of base class

When I run the following:

ParentClass foo = serializer.Deserialize(xmlReader) as ParentClass;

The xml document loaded in xmlReader is an inherited type of ParentClass. When examined in the debugger, foo is showing as being an instance of the inherited class, not the parent class. Of course, the inherited class is also of type ParentClass, but why does the as keyword have this behavior? Why doesn't C# strip out all the other object information not required to convert to ParentClass.

This is not a problem, but more or less a question out of curiosity.

Upvotes: 0

Views: 397

Answers (2)

McGarnagle
McGarnagle

Reputation: 102793

The object itself is not modified, which is why the object's type is still displayed as "ParentClass" in the debugger.

Consider the following example, which I think is illustrative. What do you think is output to the console here?

class Program
{
    public class ParentClass
    {
        public virtual void foo()
        {
            Console.WriteLine("parent.foo");
        }

        public virtual void bar()
        {
            Console.WriteLine("parent.bar");
        }
    }

    public class InheritedClass : ParentClass
    {
        public new void foo()
        {
            Console.WriteLine("inherited.foo");
        }

        public override void bar()
        {
            Console.WriteLine("inherited.bar");
        }
    }

    static void Main(string[] args)
    {
        var inherited = new InheritedClass();
        var parent = inherited as ParentClass;
        var d = parent as dynamic;

        parent.foo();
        inherited.foo();
        d.foo();

        parent.bar();
        inherited.bar();
        d.bar();

        Console.Read();
    }
}

Only one object is created, and then two more references to it are created: one with the inherited static type, and one with the "dynamic" type. That all references refer to the same object is demonstrated by the fact that invoking "bar" invokes "InheritedClass.bar" regardless of the static type (the runtime type is always the same).

However, notice the difference between using "override" and "new": you will see that "parent.foo()" invokes the "ParentClass.foo" method. That is because the "parent" variable is of the static type "ParentClass" type, and so the C# compiler emits IL instructions to call the method on "ParentClass". You can see further that the "dynamic" type reference still calls "InheritedClass.foo", because dynamic types resolve at runtime, and this resolves to the actual runtime type which is "InheritedClass".

Edit @InBetween has an important distinction that I didn't consider. In the case of casting from a value type to a reference type (or vice versa), a new object is actually created, as new memory must be allocated on the heap or stack respectively (the "boxing" process). Of course, partly for this reason, virtual methods are not supported for struct and other value types.

Upvotes: 1

InBetween
InBetween

Reputation: 32790

as can only perform reference conversions, nullable conversions, and boxing conversions. It wont perform any other type of conversions like user-defined conversions.

In your case its performing a compatible reference conversion; the object remains the same, you are only changing the reference.

But as can "modify" an object in the sense that I think you are saying when, for example, boxing which entails more than simply converting the reference.

var o = 1 as object;

o is an alltogether different object than integer 1.

It is important to note though that in any succesful as conversion GetType() will still return the original type of the object which is not the general behavior of the cast operator.

Upvotes: 1

Related Questions