4

当发现以下代码在运行时抛出异常时,我感到很惊讶:

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);
    }
}

谁能告诉我为什么?我真的不明白发生了什么

4

3 回答 3

7

你不应该感到惊讶 - 自定义运算符不会覆盖任何东西,它们会重载- 所以它们是在编译时选择的,而不是在执行时选择的。

当我们从代码中删除隐式类型时,它会更清晰一些:

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

现在很清楚,在最后一行中,(A)它只是object执行正常引用转换的强制转换。根本不会应用任何用户定义的转换。

如果您使用的是 .NET 4,则可以使用动态类型来使其工作:

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

现在转换被应用到一个动态值上,这意味着选择使用什么转换被推迟到执行时间——此时它将使用您的自定义运算符。

于 2011-08-02T12:19:57.700 回答
3

您创建了一个B. 然后将其转换为A.

尽管具有相似的布局,但 B与 A没有关系。静态运算符由编译器应用,但在运行时不通过强制转换。尽管 C# 语法相同,但它们在处理反射时却大不相同。

这是正常的预期行为。

于 2011-08-02T12:19:09.650 回答
1

你可以简单地改变这一行:

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

至:

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

所以编译器现在知道 bInstanceReflection 的类型并且可以调用正确的隐式运算符。

于 2011-09-09T15:00:11.180 回答