显式强制转换操作符应用于通过反射创建的实例



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

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

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

你不应该感到惊讶-自定义操作符不重写任何东西,它们重载 -所以它们是在编译时挑选的,而不是执行时

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

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;

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

已创建B。然后将其转换为A

尽管具有相似的布局,但B与a的没有关系。静态操作符由编译器应用,但不会在运行时通过强制转换应用。虽然c#的语法是相同的,但在处理反射时它们是非常不同的。

这是正常的,预期的行为

您可以简单地更改这一行:

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

:

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

编译器现在知道了bInstanceReflection的类型,并且可以调用正确的隐式操作符

相关内容

  • 没有找到相关文章

最新更新