泛型:转换和值类型,为什么这是非法的? [英] Generics: casting and value types, why is this illegal?

查看:31
本文介绍了泛型:转换和值类型,为什么这是非法的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么这是一个编译时错误?

Why is this a compile time error?

public TCastTo CastMe<TSource, TCastTo>(TSource i)
{
     return (TCastTo)i;
}

错误:

无法将类型TSource"转换为TCastTo"

Cannot convert type 'TSource' to 'TCastTo'

为什么这是一个运行时错误?

And why is this a runtime error?

public TCastTo CastMe<TSource, TCastTo>(TSource i)
{
     return (TCastTo)(object)i;
}

int a = 4;
long b = CastMe<int, long>(a); // InvalidCastException

// this contrived example works
int aa = 4;
int bb = CastMe<int, int>(aa);

// this also works, the problem is limited to value types
string s = "foo";
object o = CastMe<string, object>(s);

我已经在 SO 和互联网上搜索了这个问题的答案,并找到了很多关于类似的通用相关铸造问题的解释,但在这个特殊的简单案例中我找不到任何东西.

I've searched SO and the internet for an answer to this and found lots of explanations on similar generic related casting issues, but I can't find anything on this particular simple case.

推荐答案

为什么这是一个编译时错误?

Why is this a compile time error?

问题在于,每种可能的值类型组合对于强制转换的含义都有不同规则.将 64 位 double 转换为 16 位 int 与将十进制转换为浮点数等完全不同.可能性的数量是巨大的.所以像编译器一样思考.编译器应该为您的程序生成什么代码?

The problem is that every possible combination of value types has different rules for what a cast means. Casting a 64 bit double to a 16 bit int is completely different code from casting a decimal to a float, and so on. The number of possibilities is enormous. So think like the compiler. What code is the compiler supposed to generate for your program?

编译器必须生成代码,在运行时再次启动编译器,对类型进行新的分析,并动态发出适当的代码.

The compiler would have to generate code that starts the compiler again at runtime, does a fresh analysis of the types, and dynamically emits the appropriate code.

这似乎比您使用泛型获得的工作量多,性能低,所以我们干脆取缔它.如果您真正想要的是编译器再次启动并进行类型分析,请在 C# 4 中使用动态";这就是它的作用.

That seems like perhaps more work and less performance than you expected to get with generics, so we simply outlaw it. If what you really want is for the compiler to start up again and do an analysis of the types, use "dynamic" in C# 4; that's what it does.

为什么这是一个运行时错误?

And why is this a runtime error?

同样的原因.

一个装箱的 int 只能被拆箱成 int(或 int?),原因同上;如果 CLR 尝试进行从装箱值类型到所有其他可能值类型的所有可能转换,那么本质上它必须在运行时再次运行编译器.那会出乎意料地慢.

A boxed int may only be unboxed to int (or int?), for the same reason as above; if the CLR tried to do every possible conversion from a boxed value type to every other possible value type then essentially it has to run a compiler again at runtime. That would be unexpectedly slow.

那么为什么引用类型不会出错呢?

So why is it not an error for reference types?

因为每个引用类型转换都与每个其他引用类型转换相同:您询问对象以查看它是否派生自或与所需类型相同.如果不是,则抛出异常(如果进行强制转换)或导致 null/false(如果使用as/is"运算符).引用类型的规则在某种程度上是一致的,而不是值类型.记住引用类型知道它们自己的类型.值类型没有;对于值类型,进行存储的变量是唯一知道适用于这些位的类型语义的东西.值类型包含它们的值,没有附加信息.引用类型包含它们的值以及大量额外数据.

Because every reference type conversion is the same as every other reference type conversion: you interrogate the object to see if it is derived from or identical to the desired type. If it's not, you throw an exception (if doing a cast) or result in null/false (if using the "as/is" operators). The rules are consistent for reference types in a way that they are not for value types. Remember reference types know their own type. Value types do not; with value types, the variable doing the storage is the only thing that knows the type semantics that apply to those bits. Value types contain their values and no additional information. Reference types contain their values plus lots of extra data.

有关更多信息,请参阅我关于该主题的文章:

For more information see my article on the subject:

http://ericlippert.com/2009/03/03/representation-and-identity/

这篇关于泛型:转换和值类型,为什么这是非法的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆