0
votes

Looking at how the as keyword works in C#, I can see that it allows for casting where explicit casting (i.e. using brackets) prevents compilation.

However In the code below I find that if I override a method in a derived class, and then safe cast as the base class, that the overridden method in the derived class still executes. Why is this? I was expecting the method as defined on the base class to execute instead.

class Base
{
    public override string ToString()
    {
        return base.ToString();
    }

    public string OtherMethod()
    {
        return "Other method";
    }
}

class Derived : Base
{
    public override string ToString()
    {
        return "Derived class";
    }
}

class Program
{
    static void Main()
    {
        Derived d = new Derived();
        Base b = new Base();

        System.Console.WriteLine(b.ToString()); // Base
        System.Console.WriteLine(d.ToString()); // Derived class
        System.Console.WriteLine((d as Base).ToString()); // Derived class => WHY IS THIS?
        System.Console.WriteLine((d as Base).OtherMethod()); // Other method
        // System.Console.WriteLine((Base)d.OtherMethod()); // --- prevents compilation

        // As noted in the comments, this works
        System.Console.WriteLine(((Base)d).OtherMethod()); // Other method

        System.Console.ReadLine();
    }
}
3
The line marked as "prevents compilation" isn't failing because of the type of cast. It's failing because you're trying to cast the return value from OtherMethod. ((Base)d).OtherMethod() should compile just fine.Damien_The_Unbeliever
You are trying to break the polymorphism feature of object-oriented programming. Luckily you can't do that, that would be bad.Hans Passant
It calls the overridden method because the method is overridden. That's the whole point of overriding methods, so that they get called instead of the base method.Abion47
"Why is this?" The as operator doesn't change the actual type of the object in memory. It just returns a reference to this object (or a null reference if the cast fails).mm8

3 Answers

4
votes

The only time when a cast to a base-class is required and will result in the execution of a different method is when you have a case of shadowing.

Shadowing occurs when a derived class implements a method of the same name as a method in a base class1 and, explicitly, this is not an override. Usually, these are marked, instead, with the keyword new. If you have an instance of the derived class but wish to invoke the base class member, you need to cast it to that base class (or to any intermediate class in the inheritance chain that doesn't itself shadow the method in question)

In the absence of shadowing, any method invocation always uses the most derived method, based on the runtime type of the object, not the variable's declared type.

Shadowing is usually best avoided, however.


1Not necessarily the direct base class - anywhere within the chain of inheritance back to object.

0
votes

This can hopefully help: https://msdn.microsoft.com/en-us/library/ms173152.aspx

Base classes may define and implement virtualmethods, and derived classes can override them, which means they provide their own definition and implementation. At run-time, when client code calls the method, the CLR looks up the run-time type of the object, and invokes that override of the virtual method. Thus in your source code you can call a method on a base class, and cause a derived class's version of the method to be executed.

In your case you're calling the Object.ToString() virtual method, and the appropriate override is selected during runtime.

0
votes

That is just how inheritance and polymorphism works in C#. The as operator does a safe cast only, but internally its still a Derived. It just changes it so that the compiler knows it has the right types. With your types, the casting is unnecessary. This just works:

 Base d = new Derived();

This will still call the virtual methods overridden by Derived.

As for the explicit cast, its failing because it has a lower precedence than the other operators on that expression. The whole right hand side is evaluated first, then the cast. Essentially, this is what you are telling the compiler.

 string result = d.OtherMethod();
 Base result2 = (Base)d;