为什么在C#中“int []是uint [] == true”
有人可以澄清C# is
关键字请。 特别是这2个问题:
Q1)第5行; 为什么这返回真实?
Q2)第7行; 为什么没有演员异常?
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的描述没有说明情况。 它指出, is
如果这些条件得到满足将返回true。 (http://msdn.microsoft.com/en-us/library/scekt9xw(VS.71).aspx>MDSN Article)
expression is not null. expression can be cast to type.
我不相信你可以把一个有效的int []转换成uint []。 因为:
A)这段代码不能编译:
int[] signed = new int[] { -100 };
uint[] unsigned = (uint[])signed;
B)在调试器中进行强制转换会出现错误:
(uint[])signed
"Cannot convert type 'int[]' to 'uint[]'"
果然,如果第3行是int []而不是对象,那么它永远不会编译。 这给我带来了与Q2相关的最后一个问题。
Q3)为什么C#在调试器和编译器中引发了转换/转换错误,而不是在运行时呢?
C#和CLR有不同的转换规则。
您不能在C#中的int[]
和uint[]
之间直接进行转换,因为该语言不相信任何转换可用。 但是,如果通过object
则结果取决于CLI。 从CLI规范第8.7节(我希望 - 我引用了Eric Lippert前一段关于此主题的电子邮件交换):
有符号和无符号整数基元类型可以相互分配; 例如,int8:= uint8是有效的。 为此,bool应被认为与uint8
兼容,反之亦然,这使得bool := uint8
有效,反之亦然。 对于相同大小的带符号和无符号整数基元类型的数组也是如此; 例如, int32[] := uint32[]
有效。
(我没有检查,但我认为这种引用类型转换为有效的是什么使is
恢复也是如此。)
有些不幸的是,语言和底层执行引擎之间存在脱节,但从长远来看,这是不可避免的,我怀疑。 还有其他一些类似的情况,但好消息是它们似乎很少造成重大伤害。
编辑:当Marc删除他的答案时,我已经链接到来自Eric的完整邮件,发布到C#新闻组。
现在很有趣。 我在ECMA-335标准中发现了这一点。 4.3 castclass。 注意:
数组继承自System.Array。
如果Foo可以投射到Bar,那么Foo []可以投射到Bar []。
出于上述注2的目的,枚举被视为其基础类型:因此,如果E1和E2共享一个基础类型,则E1 []可以转换为E2 []。
你可以将int转换为uint,但它的行为非常奇怪。 当连接调试器时,Visual Studio不会识别出任何这一点,甚至是手表,只会显示一个问号'?'。
你可能想看看这个,快进10分钟左右,并听取安德斯解释共变阵列实现。 我认为这是这里的根本问题。
建议:
将intArray声明为“int [] intArray”而不是“object intArray”将允许编译器获取无效的C#类型转换。 除非你绝对必须使用对象,否则我会采取这种方法。
Re Q2,Q3:
在运行时,你是否尝试在一个选中的块中包装这个转换?
从MSDN的这篇文章:
默认情况下,如果表达式生成的值超出目标类型的范围,则只包含常量值的表达式会导致编译器错误。 如果表达式包含一个或多个非常量值,则编译器不会检测到溢出。
...
默认情况下,这些非常量表达式在运行时不会检查溢出,也不会引发溢出异常。 前面的示例显示-2,147,483,639为两个正整数的和。
溢出检查可以通过编译器选项,环境配置或使用checked关键字来启用。
正如它所说的,您可以通过编译器设置或环境配置来强制执行全局溢出检查。
在你的情况这可能是可取的,因为它会导致运行时错误被抛出,这将确保可能无效的无符号数字签名数字溢出不会默默地发生。
[更新]在测试了这段代码之后,我发现使用类型对象的声明而不是int []似乎绕过了标准的C#铸造sytax,无论是否启用了checked。
正如JS所说的,当你使用对象时,你受CLI规则的约束,并且这些规则显然允许发生这种情况。
Re Q1:
这与上述有关。 总之,因为涉及到的投射不会抛出异常(基于当前的溢出设置)。 这是否是一个好主意是另一个问题。
来自MSDN:
如果提供的表达式非空,则“is”表达式的计算结果为true,并且提供的对象可以转换为提供的类型而不会引发异常。
链接地址: http://www.djcxy.com/p/80655.html