显式转换为定义的类型会抛出“InvalidCastException”
Explicit cast to defined type throws `InvalidCastException`
我有一些使用显式转换操作定义的自定义包装器类型:
private class A
{
private readonly int _value;
public A(int value)
{
_value = value;
}
public int Value { get { return _value; } }
}
private class B
{
private readonly int _value;
private B(int value)
{
_value = value;
}
public int Value { get { return _value; } }
public static explicit operator B(A value)
{
return new B(value.Value);
}
}
以下工作正常:
B n = (B)new A(5);
这不是:
B n = (B)(object)new A(5);
// Throws System.InvalidCastException:
// Unable to cast object of type 'A' to type 'B'
...这是怎么回事?
我不得不首先转换为 object
- 实际转换正在通用库代码的其他地方执行(因此它的形式为 return (TOutput)(object)input;
,并且 dynamic
不是一个选项)
第一个代码片段起作用的原因是您看到的是 而不是 一个 "straight" 转换:它是一个显式转换运算符的调用。这个操作定义明确,并且完全按照编码方式工作:一个全新的对象 B
是从 A
的值构造的。 C# 有足够的信息来确定要调用显式运算符,因为 new A(5)
类型与 operator B(A value)
参数的类型相匹配。
但是,一旦您将转换添加到 object
,编译器就会进行真正的转换。 C# 不再具有适用的用户定义转换运算符,因此它进行类型检查,确定 A
不可转换为 B
,并引发异常。
有一种方法可以通过构建和编译动态 lambda 使其在没有 dynamic
的情况下工作,如下所示:
private static B ConvertFromObject(object a) {
if (a == null) return null;
var p = Expression.Parameter(typeof(object));
var c1 = Expression.Convert(p, a.GetType());
var c2 = Expression.Convert(c1, typeof(B));
var e = (Func<object,B>)Expression.Lambda(c2, p).Compile();
return e(a);
}
您可以通过 a
的 运行time 类型缓存已编译的 lambda,以节省每次 运行 该方法时编译新表达式的成本。
我有一些使用显式转换操作定义的自定义包装器类型:
private class A
{
private readonly int _value;
public A(int value)
{
_value = value;
}
public int Value { get { return _value; } }
}
private class B
{
private readonly int _value;
private B(int value)
{
_value = value;
}
public int Value { get { return _value; } }
public static explicit operator B(A value)
{
return new B(value.Value);
}
}
以下工作正常:
B n = (B)new A(5);
这不是:
B n = (B)(object)new A(5);
// Throws System.InvalidCastException:
// Unable to cast object of type 'A' to type 'B'
...这是怎么回事?
我不得不首先转换为 object
- 实际转换正在通用库代码的其他地方执行(因此它的形式为 return (TOutput)(object)input;
,并且 dynamic
不是一个选项)
第一个代码片段起作用的原因是您看到的是 而不是 一个 "straight" 转换:它是一个显式转换运算符的调用。这个操作定义明确,并且完全按照编码方式工作:一个全新的对象 B
是从 A
的值构造的。 C# 有足够的信息来确定要调用显式运算符,因为 new A(5)
类型与 operator B(A value)
参数的类型相匹配。
但是,一旦您将转换添加到 object
,编译器就会进行真正的转换。 C# 不再具有适用的用户定义转换运算符,因此它进行类型检查,确定 A
不可转换为 B
,并引发异常。
有一种方法可以通过构建和编译动态 lambda 使其在没有 dynamic
的情况下工作,如下所示:
private static B ConvertFromObject(object a) {
if (a == null) return null;
var p = Expression.Parameter(typeof(object));
var c1 = Expression.Convert(p, a.GetType());
var c2 = Expression.Convert(c1, typeof(B));
var e = (Func<object,B>)Expression.Lambda(c2, p).Compile();
return e(a);
}
您可以通过 a
的 运行time 类型缓存已编译的 lambda,以节省每次 运行 该方法时编译新表达式的成本。