为什么在C#中int 是uint == true“

请有人澄清C#关键字请。 特别是这两个问题:

Q1)第5行; 为什么这个回报是真的?

Q2)第7行; 为什么没有抛出exception?

 public void Test() { object intArray = new int[] { -100, -200 }; if (intArray is uint[]) //why does this return true? { uint[] uintArray = (uint[])intArray; //why no class cast exception? for (int x = 0; x < uintArray.Length; x++) { Console.Out.WriteLine(uintArray[x]); } } } 

MSDN的描述没有说明情况。 它表示,如果满足这些条件中的任何一个,将会返回true。 (http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx>MDSN Article)

expression式不为空。
expression式可以转换为types。

我不相信你可以做一个有效的int []到uint []中。 因为:

A)这段代码不能编译:

 int[] signed = new int[] { -100 }; uint[] unsigned = (uint[])signed; 

B)在debugging器中进行转换会出现错误:

 (uint[])signed "Cannot convert type 'int[]' to 'uint[]'" 

果然,如果第3行是int []而不是对象,那么它将永远不会编译。 这使我想到了与Q2有关的最后一个问题。

Q3)为什么C#在debugging器和编译器中提高了转换/转换错误,而不是在运行时呢?

C#和CLR有一些不同的转换规则。

您不能在C#中的int[]uint[]之间直接进行转换,因为该语言不相信任何转换可用。 但是,如果通过object进行访问,则结果取决于CLI。 从CLI规范第8.7节(我希望 – 我引用了Eric Lippert在前一段对这个主题的电子邮件交stream ):

有符号和无符号整数基本types可以相互分配; 例如,int8:= uint8是有效的。 为此,bool应被认为与uint8兼容,反之亦然,这使得bool := uint8有效,反之亦然。 对于相同大小的带符号和无符号整数基元types的数组也是如此; 例如, int32[] := uint32[]是有效的。

(我没有检查过,但是我认为这种引用types转换是有效的,那么返回值也是如此)。

语言和底层执行引擎之间存在脱节,这有点不幸,但从长远来看,这是不可避免的。 还有其他一些这样的情况,但好消息是他们似乎很less造成重大伤害。

编辑:正如马克删除他的答案,我已经链接到从埃里克的完整邮件,张贴到C#新闻组。

现在很有趣。 我在ECMA-335标准中find了这个。 4.3 castclass。 注意:

  • 数组inheritance自System.Array。

  • 如果Foo可以投射到Bar,那么Foo []可以投射到Bar []。

  • 为了上面注2的目的,枚举被视为其基础types:因此,如果E1和E2共享一个基础types,E1 []可以转换为E2 []。

你可以将int转换为uint,但是它的行为非常奇怪。 当连接debugging器的时候,Visual Studio不能识别这个,甚至是手表,只是显示一个问号“?”。

你可能想看看这个 ,快进10分钟左右,并听取安德斯解释共同arrays实施。 我认为这是根本的根本问题。

build议:

声明intArray为“int [] intArray”而不是“object intArray”将允许编译器拿起无效的C#强制转换。 除非你绝对要用对象,否则我会采取这种方法。

Re Q2,Q3:

在运行时,你是否试图在一个选中的块中包装转换?

从MSDN的这篇文章:

默认情况下,如果expression式生成的值超出了目标types的范围,则只包含常量值的expression式会导致编译器错误。 如果expression式包含一个或多个非常量值,则编译器不会检测到溢出。

默认情况下,这些非常量expression式在运行时不会被检查溢出,也不会引发溢出exception。 前面的例子显示-2,147,483,639是两个正整数的总和。

溢出检查可以通过编译器选项,环境configuration或使用checked关键字来启用。

如上所述,您可以通过编译器设置或环境configuration来强制执行全局溢出检查。

在你的情况,这可能是可取的,因为它会导致运行时错误被抛出,这将确保可能无效的无符号数字签名数字溢出不会默默地发生。

[更新]在testing这段代码之后,我发现使用types对象的声明而不是int []似乎绕过了标准的C#压铸语法,无论是否启用了checked。

正如JS所说的,当你使用对象的时候,你受到了CLI规则的约束,而这些规则显然是允许这种情况发生的。

Re Q1:

这与上面有关。 总之,因为涉及到的投射不会抛出exception(基于当前的溢出设置)。 这是否是一个好主意是另外一个问题。

来自MSDN :

如果提供的expression式为非空,则“is”expression式的计算结果为true,并且可以将所提供的对象转换为提供的types,而不会引发exception。

我猜测与.NET 1的向后兼容性:我仍然有点模糊的细节,但我相信所有数组的CLRtypes只是System.Array,具有额外的Type属性来查找元素types。 “是”可能只是没有在CLR v1中说明,现在必须保持这一点。

它不工作在(uint[])(new int[]{})情况下可能是由于C#编译器(而不是CLR运行时)能够进行更严格的types检查。

此外,数组只是键入不安全的一般:

 Animal[] tigers = new Tiger[10]; tigers[3] = new Elephant(); // ArrayTypeMismatchException 

好,

我试图刺伤这个。

首先,文档说:“检查一个对象是否与给定的types兼容”,它还说如果左边的types是“castable”(你可以毫无例外地转换)到右边的types,expression式评估为非null,则“is”关键字将评估为true

请向Jon Skeet寻求其他答案。 他比我说得更有说服力。 他是对的,如果有可用的转换,它会接受你的语法,你可以随后编写自己的语法,但是在这种情况下看起来似乎有点矫枉过正。

参考: http : //msdn.microsoft.com/en-us/library/scekt9xw(VS.80).aspx