如何在C#中将sbyte[]转换为byte[]?

37
我有一个函数可以填充类型为 sbyte[] 的数组,我需要将这个数组传递给另一个接受 byte[] 参数的函数。是否可以 在不复制所有数据或使用 unsafe 魔术的情况下进行快速转换?

刚刚在 Q 上添加了一些空格,希望您不介意 :D - Ian G
3个回答

61

是的,你可以这样做。 因为bytesbyte具有相同的二进制表示,所以不需要复制数据。 只需将其强制转换为Array,然后将其转换为byte[]就足够了。

sbyte[] signed = { -2, -1, 0, 1, 2 };
byte[] unsigned = (byte[]) (Array)signed; 

5
经常使用这种方法会收到不匹配的数组类型。 - marcelo-ferraz
1
调试器(可视化工具)似乎在处理“转换”数组时出现了问题,但它仍然可以正常工作 :) +1 - leppie
12
这个操作改变了数组的编译时类型。这是一个有用的技术,但它取决于结果的使用方式。例如,System.Array.Copy(Array, int, Array, int, int) 会检查两个数组的运行时类型,并且如果你试图将一个真正的 byte[] 复制到伪装成 byte[]sbyte[] 中,则会抛出异常。 - Cristian Diaconescu
unsigned.GetValue(0) 也会返回它的实际值 -2 - Vladimir Reshetnikov
2
我收到一个“无法将类型'sbyte []'转换为'byte []'”的错误。 - Kohanz
显示剩余4条评论

31
你需要复制数据(只有引用类型数组是协变的)- 但我们可以尝试有效地执行; Buffer.BlockCopy 似乎可以工作:
    sbyte[] signed = { -2, -1, 0, 1, 2 };
    byte[] unsigned = new byte[signed.Length];
    Buffer.BlockCopy(signed, 0, unsigned, 0, signed.Length);

如果它是引用类型,您可以直接转换引用而不复制数组:

    Foo[] arr = { new Foo(), new Foo() };
    IFoo[] iarr = (IFoo[])arr;
    Console.WriteLine(ReferenceEquals(arr, iarr)); // true

编辑以包括协变性的说明 - Marc Gravell
9
@BoiseBaked,我正在提供答案,指出他们需要复制数据并展示一种高效的方法来完成这个任务,即“提供帮助”。数组协变的上下文是相关的:在其他几乎相同的情境中,不需要复制。如果您反对使用特定术语,请不要介意。这是一个拥有复杂概念的技术领域。使用正确的术语可以避免很多混淆。这并不是“自我满足”,所以请不要摆架子了。 - Marc Gravell

6
如果您使用的是.NET 3.5+,可以使用以下内容:
byte[] dest = Array.ConvertAll(sbyteArray, (a) => (byte)a);

我想这实际上就是复制所有数据。
请注意,这个函数也适用于.NET 2.0,但您需要使用匿名方法。

唉,我宁愿使用Buffer.BlockCopy()。那至少是盲目地复制一堆字节。这个则需要为每一个字节调用一个函数。性能噩梦。 - Vilx-
1
这完全取决于你要复制多少,但是块复制更有意义。最终,如果你想要类型安全,唯一的方法就是复制。如果你想要转换(重新转换)数组,那么不安全的方式是唯一的选择。 - Clinton
笑死!或者你可以省去这个开销:byte[] foo = (byte[])(Array)signed; - BoiseBaked
2
@BoiseBaked 不可以。这不会改变数组的运行时(元素)类型。 - Frank

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