为什么在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