C# 为什么可以';难道你不能直接取消装箱到一个可以显式转换的类型吗?

C# 为什么可以';难道你不能直接取消装箱到一个可以显式转换的类型吗?,c#,.net,C#,.net,今天作为一些EF/DB代码的一部分遇到了这个,不好意思说我以前从未遇到过它 在.NET中,可以在类型之间显式强制转换。e、 g int x = 5; long y = (long)x; 您可以将其装箱到对象,然后取消装箱到原始类型 int x = 5; object y = x; int z = (int)y; 但是不能直接取消绑定到可以显式强制转换到的类型 int x = 5; object y = x; long z = (long)y; 这实际上是记录在案的行为,尽管直到今天我才真

今天作为一些EF/DB代码的一部分遇到了这个,不好意思说我以前从未遇到过它

在.NET中,可以在类型之间显式强制转换。e、 g

int x = 5;
long y = (long)x;
您可以将其装箱到对象,然后取消装箱到原始类型

int x = 5; 
object y = x;
int z = (int)y;
但是不能直接取消绑定到可以显式强制转换到的类型

int x = 5;
object y = x;
long z = (long)y;
这实际上是记录在案的行为,尽管直到今天我才真正遇到它

要在运行时成功取消绑定值类型,要取消绑定的项必须是对以前通过装箱该值类型的实例创建的对象的引用。尝试取消对null的装箱会导致NullReferenceException。尝试取消对不兼容值类型的引用的装箱会导致InvalidCastException


我很好奇,运行时不可能/不支持这一点,是否有一些技术原因?

我不知道我能简单地总结关于这个问题的所有内容,但我发现本文中与您的问题相关的部分如下:

“[有]…某些C#编译器认为是 表示更改实际上被CLR验证器视为 保留表示。例如,从int到 CLR将uint视为保留的表示,因为 有符号整数的位可以重新解释为无符号整数 这些情况可能是微妙而复杂的,而且 通常会对协方差相关问题产生影响

我还忽略了涉及泛型类型参数的转换 在编译时不知道是引用类型还是值类型 有专门的规则对那些重要的项目进行分类 要进入的离题

无论如何,我们可以考虑在 将类型引用为那些保留 对象。当你将B转换为D时,你没有对对象做任何事情 现有对象;您只是验证它实际上是类型 你说是的,然后继续。物体和比特的身份 表示引用的值保持不变。但是当您强制转换int 对于double,结果位非常不同。”

cast语法
(Foo)bar
C#执行以下操作之一:

  • 将引用类型强制转换为其他引用类型
  • 将一种值类型转换为另一种值类型
  • 框a值类型
  • 取消装箱值类型的装箱
这些操作在语义上非常不同。将它们视为四个不同的操作更为合理,这四个操作在历史上偶然地共享相同的
(Foo)bar
语法。特别是,它们对编译时需要知道的信息有不同的限制:

  • 解装箱操作需要知道解装箱值的类型
  • 值类型转换需要知道源类型和目标类型
这基本上是因为编译器需要在编译时知道分配给值的字节数。在您的示例中,装箱值为
int
的信息在编译时不可用,这意味着无法编译取消装箱或转换为
long

这里与直觉相反的是,相同的约束不适用于引用类型。实际上,转换引用类型的全部要点是编译器在编译时不知道确切的类型。当您比编译器更了解并接受强制转换时,您可以使用强制转换,然后在运行时执行类型检查以确保强制转换有效

由于参考类型的一些基本差异,这是可能的:

  • 引用类型实例在运行时知道自己的确切类型。它作为实例数据的一部分存储
  • 引用类型是多态的,这意味着编译器不需要知道确切的实例类型。所有引用都具有相同的大小,因此分配多少字节没有歧义
不同类型强制转换之间的这些语义差异意味着它们不能在不影响安全性的情况下进行合并

假设在单个强制转换表达式中支持C#unbox和convert:

int x = 70000;
object y = x;
short z = (short)y;
当前,取消装箱转换表示您希望装箱的值为给定类型。如果不是这样,则会引发异常,因此您会发现错误。但是使用cast语法进行值类型转换表示您知道类型不同,并且转换可能导致数据丢失


如果语言会自动取消装箱和转换,那么就无法表示您是否希望安全地取消装箱而不存在任何数据丢失的风险

@MrAnderson,因为枚举的基本类型是
int
。这是编写编译器的人员的额外工作,他们需要弄清楚,要将装箱的int转换为long,首先需要取消装箱,然后再加宽。为此,编译器需要发出代码,在运行时检查装箱值的类型,然后决定要做什么:
int
to
int
->没问题,
int
to
long
->加宽值,
int
double
->更改所有位……然后,您在代码中执行的每一次转换都需要这样做。我想,与开发人员在极少数情况下需要额外演员阵容时所做的少量额外工作相比,这需要大量额外的代码和性能提升。你是否正确地重读了Eric的文章?“这将需要生成大量代码,而且速度非常慢。代码当然非常大,您可能希望将其放入自己的方法中,然后生成对它的调用……它是可用的–您可以随时调用
Convert.ToInt32
,它在运行时为您进行所有分析。我们为您提供了choi