4

I was suprised when found that the following code throws exception at runtime:

class A
{
    public string Name { get; set; }

    public A()
    {
        Name = "Class A";
    }
}

class B
{
    public string Name { get; set; }

    public B()
    {
        Name = "Class B";
    }

    public static explicit operator A(B source)
    {
        return new A() {Name = source.Name};
    }
}


class Program
{
    static void Main(string[] args)
    {
        // This executes with no error
        var bInstance = new B();
        Console.WriteLine(bInstance.GetType()); // <assemblyname>.B
        var aInstance = (A) bInstance;
        Console.WriteLine(aInstance.Name); // Class B

        // This fails with InvalidCastException
        var bInstanceReflection = Activator.CreateInstance(typeof (B));
        Console.WriteLine(bInstanceReflection.GetType()); // <assemblyname>.B
        var aInstanceReflection = (A) bInstanceReflection;

        Console.WriteLine(aInstanceReflection.Name);
    }
}

Could anyone tell me why? I don't really understand what happened

0

3 Answers 3

7

You shouldn't be surprised - custom operators don't override anything, they overload - so they're picked at compile time, not execution time.

When we remove implicit typing from the code, it makes it a bit clearer:

object bInstanceReflection = Activator.CreateInstance(typeof (B));
Console.WriteLine(bInstanceReflection.GetType()); // <assemblyname>.B
A aInstanceReflection = (A) bInstanceReflection;

Now it's reasonably clear that in the final line, (A) is just a cast from object which performs the normal reference conversion. No user-defined conversions will be applied at all.

If you're using .NET 4, you can use dynamic typing to get it to work:

// Note the change of type
dynamic bInstanceReflection = Activator.CreateInstance(typeof (B));
Console.WriteLine(bInstanceReflection.GetType()); // <assemblyname>.B
A aInstanceReflection = (A) bInstanceReflection;

Now the conversion is being applied on a dynamic value, which means the choice of what conversion to use is deferred until execution time - at which point it will use your custom operator.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Jon, your post is very useful for me!
3

You've created a B. And then cast it to an A.

Despite having similar layouts, B has no relationship to A. Static operators are applied by the compiler, but not at runtime via cast. Although the C# syntax is the same, they are very different when dealing with reflection.

This is the normal, expected behaviour.

1 Comment

Thanks Marc, it was really new for me. I also found Eric Lippert answer to the similar question stackoverflow.com/questions/2090092/…
1

You can simply change this line:

var bInstanceReflection = Activator.CreateInstance(typeof (B));

To:

var bInstanceReflection = (B)Activator.CreateInstance(typeof (B));

So the compiler now knows the type of bInstanceReflection and can call the correct implitic operator.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.