C# 表达式.Convert不';是否为不变值类型参数引发InvalidOperationException?

C# 表达式.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。表达式树可以正确编译,但是当我调用创建

通常在“expression.Type和Type之间未定义转换运算符”时抛出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 );
    }