sbyte[]可以神奇地转换为byte[]。

21

我不确定这是否是.NET的bug,但我觉得它非常有趣。

如预期的那样,我无法做到这一点:

sbyte[] sbytes = { 1, 2, 3 };
byte[] bytes = sbytes; // fails: cannot convert source type 'sbyte[]' to taget type 'byte[]'

然而,如果sbytes的类型为object,那么这样可以工作:

object obj = new sbyte[]{ 1, 2, 3 };
byte[] bytes = obj as byte[];
Assert.IsNull(bytes, "WTF??")

备注1: 对于int[] - uint[]和其他基本类型也会出现同样的问题。

备注2: 虽然代码将数组处理为byte[],但调试器失去了焦点,在数组中显示?

截图

备注3: 这仅适用于数组本身,而不适用于底层类型本身:

object sbyteObj = (sbyte)1;
byte byteObj = (byte)sbyteObj; // System.InvalidCastException: Specified cast is not valid.

好的,我当然可以这样检查类型:

if (obj.GetType() == typeof(byte[]))

这是 as 操作符和直接类型转换的预期行为,还是一个 .NET 的 bug?


那些问号?我没有这种行为。尝试禁用优化代码。 - M.kazem Akhgary
1个回答

27

不,这不是一个错误。这只是C#语言规则与CLR规则之间的阻抗失配(C#语言规则声称不存在转换,而CLR规则中存在该转换)。

请注意编译器确实非常认为它知道得最好:

byte[] bytes = new byte[10];
// error CS0030: Cannot convert type 'byte[]' to 'sbyte[]'
sbyte[] sbytes = (sbyte[]) bytes; 

即使你的代码能够编译通过并显示警告,它也不能真正实现其所述功能:

byte[] bytes = new byte[10];
// warning CS0184: The given expression is never of the provided ('sbyte[]')
if (bytes is sbyte[])
{
    Console.WriteLine("Yes");
}
运行该代码时,您将不会得到任何输出...但是如果您仅更改bytes的编译时类型,则会打印出Yes:
object bytes = new byte[10];
// No warning now
if (bytes is sbyte[])
{
    Console.WriteLine("Yes"); // This is reached
}

好的,知道“is”,“as”和直接转换并不总是可靠的,至少对于原始类型的数组是如此。 - György Kőszeg
@taffer:不太确定你所说的“不完全可靠”的意思。如果你知道是编译器在尝试检查,还是发生在执行时,你就可以确切地知道会发生什么。 - Jon Skeet
如果我知道框架的小诀窍,当然我总能预测会发生什么。 :) 顺便说一下,我刚刚检查了一下,这些症状出现在大小相同的基本类型中,除了charbool之外,还包括IntPtrUIntPtr。即使在您的回答之后,我也不能说我能够预测这种行为。 - György Kőszeg
@taffer:顺便提一下,你也可以在枚举数组和枚举底层类型的数组之间进行转换。我认为CLI规范给出了详细说明... - Jon Skeet
是的,但这也可以在没有数组的情况下工作。因此,我可以从存储枚举的对象中取消装箱int。但是,从具有byte的对象中取消装箱sbyte会引发InvalidCastException异常。 - György Kőszeg
@taffer:没错 - 我相信 C# 的这部分行为以及 CLR 已经有文档记录了,不过我没有完全记住。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接