当发现以下代码在运行时抛出异常时,我感到很惊讶:
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);
}
}
有人可以告诉我为什么吗?我真的不明白发生了什么
答案 0 :(得分: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;
现在转换正在应用于动态值,这意味着选择要使用的转换延迟到执行时间 - 此时它将使用您的自定义运算符。
答案 1 :(得分:3)
您已创建B
。然后将其转换为A
。
尽管有类似的布局,但B与没有关系到A.静态运算符由编译器应用,但不是在运行时通过强制转换。虽然C#语法是相同的,但在处理反射时它们是非常不同的。
这是正常的预期行为。
答案 2 :(得分:1)
您只需更改此行:
var bInstanceReflection = Activator.CreateInstance(typeof (B));
要:
var bInstanceReflection = (B)Activator.CreateInstance(typeof (B));
因此编译器现在知道bInstanceReflection的类型,并且可以调用正确的implitic操作符。