对于不变值类型参数,Expression.Convert 不会抛出 InvalidOperationException 吗?

发布于 2024-12-13 08:52:26 字数 2005 浏览 4 评论 0原文

Expression.Convert 通常会抛出 < code>InvalidOperationException 当“在表达式.Type 和类型之间没有定义转换运算符。”

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

  1. 这是一个错误吗? (我将其报告为 Microsoft Connect 上的错误。)
  2. 如何正确检查一种类型是否可以转换为另一种类型? 一些答案​​似乎是指使用Convert。我非常喜欢一种不必使用异常处理作为逻辑的方法。

似乎整个方差逻辑没有得到适当的支持。它正确地抱怨无法从 Func 转换为 Func,但它不会抱怨从 Func转换为 Func。 到 Func

有趣的是,一旦 SomeTypeSomeOtherType 位于同一类层次结构中(SomeOtherTypeSomeType 扩展),它就不会抛出异常例外。如果不是,那就是。

Expression.Convert generally throws in InvalidOperationException when "No conversion operator is defined between expression.Type and type."

The return type parameter of Func<> is covariant for reference types.

// This works.
Func<SomeType> a = () => new SomeType();
Func<object> b = a;

It isn't covariant for value types.

Variance applies only to reference types; if you specify a value type for a variant type parameter, that type parameter is invariant for the resulting constructed type.

// This doesn't work!
Func<int> five = () => 5;
Func<object> fiveCovariant = five;

However, Expression.Convert believes it is possible.

Func<int> answer = () => 42;
Expression answerExpression = Expression.Constant( answer );
// No InvalidOperationException is thrown at this line.
Expression converted 
    = Expression.Convert( answerExpression, typeof( Func<object> ) );

No InvalidOperationException is thrown when calling Expression.Convert. The expression tree compiles correctly, but when I call the created delegate, I get an expected InvalidCastException.

  1. Is this a bug? (I reported it as a bug on Microsoft Connect.)
  2. How to properly check whether a type can be converted to another type? Some answers seem to refer to using Convert. I would very much prefer a method which doesn't have to use exception handling as logic.

It seems the entire variance logic isn't properly supported. It correctly complains about not being able to convert from Func<SomeType> to Func<SomeOtherType>, but it doesn't complain about converting from Func<object> to Func<string>.

Interestingly, once SomeType and SomeOtherType are in the same class hierarchy (SomeOtherType extends from SomeType), it never throws the exception. If they aren't, it does.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

孤者何惧 2024-12-20 08:52:26

这是一个错误吗?

是的。当我们添加协变和逆变时,表达式树库可能没有始终如一地更新。对此感到抱歉。

我将其报告为 Microsoft Connect 上的错误。

谢谢!到时候会有人来看看的。

如何正确检查一种类型是否可以转换为另一种类型?

问题很模糊。给定两个类型对象,您想知道:

  • .NET 运行时是否认为这些类型是赋值兼容的?
  • C#编译器是否认为类型之间存在隐式转换?
  • C# 编译器是否认为类型之间存在显式转换?

例如,“int”和“short”与 .NET 规则的赋值不兼容。 Int 可以显式转换,但不能隐式转换为 Short,而根据 C# 规则,short 可以隐式和显式转换为 int。

Is this a bug?

Yes. The expression tree library was probably not updated consistently throughout when we added covariance and contravariance. Sorry about that.

I reported it as a bug on Microsoft Connect.

Thanks! Someone will have a look at it then.

How to properly check whether a type can be converted to another type?

The question is vague. Given two type objects, do you want to know:

  • Does the .NET runtime think the types are assignment compatible?
  • Does the C# compiler think that there is an implicit conversion between the types?
  • Does the C# compiler think that there is an explicit conversion between the types?

"int" and "short" for example are not assignment compatible by .NET rules. Int is explicitly convertible but not implicitly convertible to short, and short is both implicitly and explicitly convertible to int, by C# rules.

夏见 2024-12-20 08:52:26

这不是一个错误。 Expression.Convert 表示运行时类型检查,因此运行时的 InvalidCastException 将是预期的行为。

编辑:这并不完全正确。它并不完全代表运行时类型检查(以下是文档:http: //msdn.microsoft.com/en-us/library/bb292051.aspx)。但是,表达式树是在运行时创建的,因此所有类型检查都必须在此时进行。

编辑:我也在使用 .NET 4.0。

顺便说一句,Convert 不会抱怨从 Func转换为 Func ,因为这种转换有时是合法。。如果 Func是对运行时类型为 Func 的对象的协变引用,则这是合法的。示例:

Func<string> sFunc = () => "S";
Func<object> oFunc = sFunc;
Func<string> anotherSFunc = (Func<string>)oFunc;

现在,Convert 通过检查一种类型是否可以强制为另一种类型来决定是否抛出 InvalidOperationException。在检查委托是否存在潜在的引用转换时,代码似乎会检查逆变(参数)参数,如果有任何参数是值类型,则会抛出 InvalidOperationException 。它似乎没有对协变(返回类型)参数进行检查。因此,我开始怀疑这是一个错误,尽管我倾向于保留对此的判断,直到我有机会查看规范(请参阅 Eric Lippert 的 也许宇宙出了点问题,但也可能不是),我现在没时间这么做。

It's not a bug. Expression.Convert represents a run-time type check, so an InvalidCastException at run time would be the expected behavior.

Edit: that's not entirely correct. It doesn't exactly represent a run-time type check (Here's the documentation: http://msdn.microsoft.com/en-us/library/bb292051.aspx). However, the expression tree is created at run-time, so all the type checking must happen then.

Edit: I'm using .NET 4.0 too.

By the way, Convert doesn't complain about converting from Func<object> to Func<string> because that conversion is sometimes legal. It is legal if the Func<object> is a covariant reference to an object whose runtime type is Func<string>. Example:

Func<string> sFunc = () => "S";
Func<object> oFunc = sFunc;
Func<string> anotherSFunc = (Func<string>)oFunc;

Now, Convert decides whether to throw an InvalidOperationException by checking whether one type can be coerced to another. When checking delegates for a potential reference conversion, it looks like the code does check contravariant (argument) parameters and throws an InvalidOperationException if any is a value type. It doesn't seem to do that check for the covariant (return type) parameter. So I am beginning to suspect that this is a bug, though I'm inclined to reserve judgment on that until I have a chance to look at the spec (see Eric Lippert's Maybe there's something wrong with the universe, but probably not), which I don't have time to do right now.

动次打次papapa 2024-12-20 08:52:26

Eric Lippert 回答了我问题的第一部分:这似乎是一个错误。我开始寻找问题2的解决方案:

如何正确检查一种类型是否可以转换为另一种类型?

我只是第一次尝试 Type.CanConvertTo( Type to ) 方法 到我的库。 (来源太复杂,无法在此处发布,抱歉。)

if ( fromType.CanConvertTo( toType ) )
{
    convertedExpression = Expression.Convert( expression, toType );
}

到目前为止,它支持检查以下内容的隐式转换

  • 简单的非泛型类型。
  • 嵌套通用接口和委托的变体。
  • 通用值类型参数的不变性。

它不支持:

  • 类型约束。
  • 自定义隐式转换运算符。

它通过 所有我对隐式转换的测试。尽管您也可以指定包含显式转换(实际上我 现在就这样使用),我仍然需要为所有这些场景编写单元测试。

Eric Lippert answered part 1 of my question: it seems to be a bug. I started looking for a solution to question 2:

How to properly check whether a type can be converted to another type?

I just commit a first attempt at a Type.CanConvertTo( Type to ) method to my library. (Sources are way too complex to post here, sorry.)

if ( fromType.CanConvertTo( toType ) )
{
    convertedExpression = Expression.Convert( expression, toType );
}

So far it supports checking implicit conversions for:

  • Simple non-generic types.
  • Variance for nested generic interfaces and delegates.
  • Invariance for generic value type parameters.

It doesn't support:

  • Type constraints.
  • Custom implicit conversion operators.

It passes all my tests for implicit conversions. Although you can specify to include explicit conversions as well (and I actually use it like that at the moment), I still need to write unit tests for all those scenarios.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文