表达式.Convert不会为不变值类型参数抛出InvalidOperationException
本文关键字:类型参数 InvalidOperationException Convert 表达式 | 更新日期: 2023-09-27 18:12:50
Expression.Convert
通常在"表达式之间没有定义转换操作符时抛出InvalidOperationException
。打字和打字。"
对于引用类型,Func<>
的返回类型参数是协变的。
// This works.
Func<SomeType> a = () => new SomeType();
Func<object> b = a;
对于值类型它不是协变的
方差只适用于引用类型;如果为变体类型参数指定值类型,则该类型参数对于生成的构造类型是不变的。
// This doesn't work!
Func<int> five = () => 5;
Func<object> fiveCovariant = five;
然而,Expression.Convert
相信这是可能的。
Func<int> answer = () => 42;
Expression answerExpression = Expression.Constant( answer );
// No InvalidOperationException is thrown at this line.
Expression converted
= Expression.Convert( answerExpression, typeof( Func<object> ) );
调用Expression.Convert
时没有抛出InvalidOperationException
。表达式树编译正确,但是当我调用创建的委托时,我得到了预期的InvalidCastException
。
- 这是一个bug吗?(我在Microsoft Connect上报告了一个bug)
- 如何正确检查一种类型是否可以转换为另一种类型?一些答案似乎是指使用
Convert
。我非常喜欢不需要使用异常处理作为逻辑的方法。
似乎整个方差逻辑没有得到正确支持。它正确地抱怨不能从Func<SomeType>
转换到Func<SomeOtherType>
,但它没有抱怨从Func<object>
转换到Func<string>
。
有趣的是,一旦SomeType
和SomeOtherType
在同一个类层次结构中(SomeOtherType
从SomeType
扩展),它就不会抛出异常。
这是一个bug吗?
是的。当我们添加协方差和逆变时,表达式树库可能没有持续更新。很抱歉。
我把它报告为Microsoft Connect的bug。
谢谢!到时候会有人来看看的。
如何正确检查一个类型是否可以转换为另一个类型?
这个问题很模糊。给定两个类型对象,您想知道:
- .NET运行时认为类型是赋值兼容的吗? c#编译器认为类型之间存在隐式转换吗?c#编译器认为类型之间有显式转换吗?
"int"answers"short"在。net规则中不兼容赋值。Int可以显式转换,但不能隐式转换为short,根据c#规则,short可以隐式和显式转换为Int。
这不是bug。表达式。Convert表示运行时类型检查,因此运行时的InvalidCastException将是预期的行为。
编辑:这并不完全正确。它并不完全代表运行时类型检查(这里是文档:http://msdn.microsoft.com/en-us/library/bb292051.aspx)。然而,表达式树是在运行时创建的,所以所有的类型检查都必须在运行时进行。
编辑:我也在用。net 4.0。
顺便说一下,Convert
没有抱怨从Func<object>
转换到Func<string>
,因为这种转换有时是合法的。如果Func<object>
是对运行时类型为Func<string>
的对象的协变引用,则它是合法的。例子:Func<string> sFunc = () => "S";
Func<object> oFunc = sFunc;
Func<string> anotherSFunc = (Func<string>)oFunc;
现在,Convert通过检查一种类型是否可以强制转换为另一种类型来决定是否抛出InvalidOperationException。在检查委托是否存在潜在的引用转换时,看起来代码确实检查了逆变(实参)形参,如果有值类型,则抛出InvalidOperationException
。它似乎没有检查协变(返回类型)参数。所以我开始怀疑这个是一个bug,尽管我倾向于保留判断,直到我有机会看看规范(见Eric Lippert的"也许宇宙有问题,但也可能没有"),我现在没有时间做。
Eric Lippert回答了我问题的第一部分:这似乎是一个bug。我开始寻找问题2的解决方案:
如何正确检查一个类型是否可以转换为另一个类型?
我刚刚向我的库提交了Type.CanConvertTo( Type to )
方法的第一次尝试。(来源太复杂了,不好意思在这里发布)
if ( fromType.CanConvertTo( toType ) )
{
convertedExpression = Expression.Convert( expression, toType );
}
到目前为止,它支持检查隐式转换- 简单非泛型类型
- 嵌套的泛型接口和委托的方差
- 泛型值类型参数的不变性。
不支持:
- 类型约束。
- 自定义隐式转换操作符。
它通过了所有隐式转换的测试。尽管您也可以指定包括显式转换(实际上我现在就是这样使用它的),但我仍然需要为所有这些场景编写单元测试。