2
class Base
{
}

class Derived1 : Base
{
}

class Derived2 : Base
{
    public static explicit operator Derived1(Derived2 d2)
    {
        return new Derived1();
    }
}

class Test
{
    static void Main()
    {
        Base bd2 = new Derived2();

        Derived1 d2ConvertedD1 = (Derived1)bd2; //throws InvalidCastException

    }
}

Unable to cast object of type 'ConsoleApplication1.Derived2' to type 'ConsoleApplication1.Derived1'.

Why? What is wrong with my operator conversion?

George Stocker
  • 57,289
  • 29
  • 176
  • 237
Budda
  • 18,015
  • 33
  • 124
  • 206

5 Answers5

10

The trouble is that your custom conversion isn't being used, because the compile-time type of bd2 is Base, not Derived2. The compiler isn't even considering your custom conversion, so it's just including a normal cast - which is failing for the obvious reason. (I assume you understand that failure, otherwise you wouldn't have created the custom conversion to start with.)

Operators and conversions are chosen by the compiler based on the compile-time types of the operands.

While you could cast to Derived2 first or change the declaration of bd2, I would personally change tack completely, and look at the bigger picture again. What are you trying to do, and why? Would a virtual method in Base make more sense, for example?

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • That is just an abstract thinking, there are no any business usage here. I'm just want to know better casting operator (though they are not recommended to use). Thank you for your help. – Budda Feb 17 '11 at 16:34
5

You can only cast classes up and down the hierarchy, not across.

bjornars
  • 1,506
  • 2
  • 10
  • 13
1

Look at the signature of your operator:

public static explicit operator Derived1(Derived2 d2);

Notice it's static. What you're seeing is similar to the limitation of method overload resolution.

It's essentially the same reason the below outputs "Object" instead of "String":

static void WriteObject(object obj) { Console.WriteLine("Object"); }
static void WriteObject(string str) { Console.WriteLine("String"); }

object obj = "I am a string.";
WriteObject(obj);

That is, the compiler needs to pick an overload at compile-time. In the case of casting from a Base to a Derived1, there is no overload with the proper signature, so it attempts an actual downcast. Declaring bd2 as Derived2, as others have mentioned, would "fix" this by enabling the compiler to select your custom conversion.

Dan Tao
  • 125,917
  • 54
  • 300
  • 447
0

The class Derived2 does not inherit from the class Derived1, that is why this fails.

The following would be valid:

Base d2ConvertedBase = (Base) bd2;

If Derived2 was to inherit from Derived1, what you tried would be valid.

WiseGuyEh
  • 18,584
  • 1
  • 20
  • 20
  • See my comment to bjornars - the point is that the custom conversion isn't being called. – Jon Skeet Feb 08 '11 at 15:49
  • Thanks for clarifying. The original post was somewhat hard to decipher without that lovely C# formatting but no excuse for my less than thorough reading – WiseGuyEh Feb 08 '11 at 16:07
0

Cast to the base class. If you're creating a complex class heirarchy, consider implementing interfaces and doing interface based programming.

Shan Plourde
  • 8,528
  • 2
  • 29
  • 42