我正在寻找一种方法来重新解释byte []类型的数组作为一个不同的类型,比如short [].在C++中,这可以通过简单的转换实现,但在C#中,我没有找到实现这一目的的方法,而不需要复制整个缓冲区.
有任何想法吗?
San*_*der 10
你可以做到这一点,但这是一个相对糟糕的主意.像这样的原始内存访问不是类型安全的,只能在完全信任的安全环境下完成.您绝不应该在设计合理的托管应用程序中执行此操作.如果您的数据伪装成两种不同的形式,那么您实际上可能有两个独立的数据集?
无论如何,这里有一个快速简单的代码片段来完成你的要求:
byte[] bytes = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int byteCount = bytes.Length;
unsafe
{
// By using the fixed keyword, we fix the array in a static memory location.
// Otherwise, the garbage collector might move it while we are still using it!
fixed (byte* bytePointer = bytes)
{
short* shortPointer = (short*)bytePointer;
for (int index = 0; index < byteCount / 2; index++)
{
Console.WriteLine("Short {0}: {1}", index, shortPointer[index]);
}
}
}
Run Code Online (Sandbox Code Playgroud)
这个问题有四个很好的答案。每个都有不同的缺点。当然,要注意字节顺序并意识到所有这些答案都是类型系统中的漏洞,而不是特别危险的漏洞。简而言之,不要经常这样做,并且只有在您真正需要时才这样做。
桑德的回答。使用不安全代码重新解释指针。这是最快的解决方案,但它使用了不安全的代码。并不总是一种选择。
列奥尼达的回答。使用StructLayout和FieldOffset(0)将结构转换为联合。这样做的缺点是一些(罕见的)环境不支持 StructLayout(例如 Flash 构建在 Unity3D 中)并且 StructLayout 不能与泛型一起使用。
ljs的回答。使用BitConverter方法。这样做的缺点是大多数方法分配内存,这在低级代码中不是很好。此外,没有一套完整的这些方法,因此您不能真正通用地使用它。
Buffer.BlockCopy两个不同类型的数组。唯一的缺点是你需要两个缓冲区,这在转换数组时是完美的,但在转换单个值时会很痛苦。请注意长度以字节为单位指定,而不是元素。Buffer.ByteLength有帮助。此外,它仅适用于原语,如整数、浮点数和布尔值,而不适用于结构体或枚举。
但是你可以用它做一些巧妙的事情。
public static class Cast {
private static class ThreadLocalType<T> {
[ThreadStatic]
private static T[] buffer;
public static T[] Buffer
{
get
{
if (buffer == null) {
buffer = new T[1];
}
return buffer;
}
}
}
public static TTarget Reinterpret<TTarget, TSource>(TSource source)
{
TSource[] sourceBuffer = ThreadLocalType<TSource>.Buffer;
TTarget[] targetBuffer = ThreadLocalType<TTarget>.Buffer;
int sourceSize = Buffer.ByteLength(sourceBuffer);
int destSize = Buffer.ByteLength(targetBuffer);
if (sourceSize != destSize) {
throw new ArgumentException("Cannot convert " + typeof(TSource).FullName + " to " + typeof(TTarget).FullName + ". Data types are of different sizes.");
}
sourceBuffer[0] = source;
Buffer.BlockCopy(sourceBuffer, 0, targetBuffer, 0, sourceSize);
return targetBuffer[0];
}
}
class Program {
static void Main(string[] args)
{
Console.WriteLine("Float: " + Cast.Reinterpret<int, float>(100));
Console.ReadKey();
}
}
Run Code Online (Sandbox Code Playgroud)