当发现以下代码在运行时抛出异常时,我感到很惊讶:
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的类型,并且可以调用正确的隐式操作符