C# 表达式.Convert不';是否为不变值类型参数引发InvalidOperationException?
通常在“expression.Type和Type之间未定义转换运算符”时抛出InvalidOperationExceptionC# 表达式.Convert不';是否为不变值类型参数引发InvalidOperationException?,c#,expression-trees,covariance,contravariance,C#,Expression Trees,Covariance,Contravariance,通常在“expression.Type和Type之间未定义转换运算符”时抛出InvalidOperationException Func的返回类型参数对于引用类型是协变的 // This works. Func<SomeType> a = () => new SomeType(); Func<object> b = a; 调用Expression.Convert时不会引发任何InvalidOperationException。表达式树可以正确编译,但是当我调用创建
Func
的返回类型参数对于引用类型是协变的
// This works.
Func<SomeType> a = () => new SomeType();
Func<object> b = a;
调用Expression.Convert
时不会引发任何InvalidOperationException
。表达式树可以正确编译,但是当我调用创建的委托时,会得到一个预期的InvalidCastException
Convert
。我非常喜欢一种不必使用异常处理作为逻辑的方法似乎整个方差逻辑没有得到正确的支持。它正确地抱怨无法从
Func
转换到Func
,但它不会抱怨从Func
转换到Func
有趣的是,一旦SomeType
和SomeOtherType
在同一类层次结构中(SomeOtherType
从SomeType
扩展),它就不会抛出异常。如果它们不是,它就是。这不是一个bug。Convert表示运行时类型检查,因此运行时的InvalidCastException将是预期行为
编辑:这不完全正确。它并不完全代表运行时类型检查(以下是文档:)。但是,表达式树是在运行时创建的,因此所有类型检查都必须在运行时进行
编辑:我也在使用.NET4.0
顺便说一下,Convert
并不抱怨从Func
转换为Func
,因为这种转换有时是合法的。如果Func
是对运行时类型为Func
的对象的协变引用,则这是合法的。例如:
Func<string> sFunc = () => "S";
Func<object> oFunc = sFunc;
Func<string> anotherSFunc = (Func<string>)oFunc;
Func-sFunc=()=>“S”;
Func=sFunc;
Func另一个Func=(Func);
现在,Convert通过检查一种类型是否可以强制到另一种类型来决定是否抛出InvalidOperationException。检查委托是否存在潜在的引用转换时,代码似乎会检查逆变(参数)参数,并抛出invalidoOperationException
(如果有)值类型。它似乎没有检查协变(返回类型)参数。所以我开始怀疑这是一个bug,尽管我倾向于保留对它的判断,直到我有机会看一下规范(见Eric Lippert的),我现在没有时间去做
这是虫子吗
对。当我们添加协方差和反方差时,表达式树库的更新可能并不一致。很抱歉
我将其报告为Microsoft Connect上的错误
谢谢!到时候会有人来看看的
如何正确检查一种类型是否可以转换为另一种类型
这个问题很模糊。给定两个类型对象,是否要知道:
- NET运行时是否认为这些类型与赋值兼容
- C#编译器是否认为类型之间存在隐式转换
- C#编译器是否认为类型之间存在显式转换
例如,“int”和“short”与.NET规则的赋值不兼容。Int可以显式转换,但不能隐式转换为short,根据C#规则,short可以隐式和显式转换为Int。Eric Lippert回答了我问题的第一部分:它似乎是一个bug。我开始寻找问题2的解决方案: 如何正确检查一种类型是否可以转换为另一种类型 我只是第一次尝试使用
Type.CanConvertTo(Type to)
方法。(来源太复杂,无法在此发布,抱歉。)
到目前为止,它支持检查隐式转换:
- 简单的非泛型类型
- 嵌套泛型接口和委托的差异
- 泛型值类型参数的不变性
- 类型约束
- 自定义隐式转换运算符
它过去了。虽然您也可以指定包含显式转换(实际上是我),但我仍然需要为所有这些场景编写单元测试。准确地说,这样它就知道无法将
Func
转换为Func
?例如,它知道无法将Func
转换为Func
。编辑:看来它也不知道O@StevenJeuris确切地关键是,无论Convert知道什么,它只能在运行时知道它。编译器不进行静态分析。因此,您可以使用各种非法转换调用Convert,这些调用将被编译。在代码运行之前,它们不会失败。这就是为什么我投了反对票,这不是真的。试试看。其他SE问题实际上是指使用异常Convert
throws来检查转换到给定类型是否会成功。(很抱歉,无法立即找到它。)此外,它似乎甚至可以对泛型类型执行某种形式的类型参数检查,因为在我的更新中不允许使用Func
到Func
。@Stevenjeris您的评论让我困惑:Func
可转换为Func
Func
不能转换为Func
。通过表达式实现每个转换。然而,Convert是编译的。他并没有要求编译器出错;他在编译表达式而不是运行表达式时请求异常。“给定两个类型对象,您想知道吗”:如:“expression.type和type之间未定义任何转换运算符。”目前,在运行表达式树之前,我无法知道表达式树是否表示有效代码。为了我的
Func<int> answer = () => 42;
Expression answerExpression = Expression.Constant( answer );
// No InvalidOperationException is thrown at this line.
Expression converted
= Expression.Convert( answerExpression, typeof( Func<object> ) );
Func<string> sFunc = () => "S";
Func<object> oFunc = sFunc;
Func<string> anotherSFunc = (Func<string>)oFunc;
if ( fromType.CanConvertTo( toType ) )
{
convertedExpression = Expression.Convert( expression, toType );
}