9

好的,我想要做的基本想法是将字节数组转换为短或整数等。

一个简单的例子可能是:

        unsafe
        {
            fixed (byte* byteArray = new byte[5] { 255, 255, 255, 126, 34 })
            {
                short shortSingle = *(short*)byteArray;
                MessageBox.Show((shortSingle).ToString()); // works fine output is -1
            }
        }

好的,所以我真正想做的是,对 Stream 类进行扩展;扩展读写方法。我需要以下代码的帮助:

unsafe public static T Read<T>(this Stream stream)
        {
            int bytesToRead = sizeof(T); // ERROR: Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')
            byte[] buffer = new byte[bytesToRead];
            if (bytesToRead != stream.Read(buffer, 0, bytesToRead))
            {
                throw new Exception();
            }
            fixed (byte* byteArray = buffer)
            {
                T typeSingle = *(T*)byteArray; // ERROR: Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')
                return typeSingle;
            }
        }

        unsafe public static T[] Read<T>(this Stream stream, int count)
        {
             // haven't figured out it yet. This is where I read and return T arrays
        }

我觉得我必须使用指针来提高速度,因为我将致力于从 NetworkStream 类等流中写入和读取数据。谢谢你的帮助!

编辑:

当我试图弄清楚如何返回 T 数组时,我遇到了这个问题:

unsafe
        {
            fixed (byte* byteArray = new byte[5] { 0, 0, 255, 255, 34 })
            {
                short* shortArray = (short*)byteArray;
                MessageBox.Show((shortArray[0]).ToString()); // works fine output is 0
                MessageBox.Show((shortArray[1]).ToString()); // works fine output is -1

                short[] managedShortArray = new short[2];
                managedShortArray = shortArray; // The problem is, How may I convert pointer to a managed short array? ERROR: Cannot implicitly convert type 'short*' to 'short[]'
            }
        }

总结:我必须从字节数组转换为给定类型的 T 或给定长度的给定类型的 T 数组

4

2 回答 2

5

由于 C# 中的指针限制,您不能将此函数设为通用函数。以下任何类型都可以是指针类型:

  • sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal 或 bool。
  • 任何枚举类型。
  • 任何指针类型。
  • 任何仅包含非托管类型字段的用户定义结构类型。

但是您不能对 T 设置限制where T <can be pointer type>where T : struct非常接近,但还不够,因为用户定义的结构可以包含引用类型的字段。

有一种解决方法 - System.Runtime.InteropServices.Marshal.PtrToStructure()(如果它无法使用指定的对象类型,它只会抛出异常),但它也会扼杀任何已实现的性能改进。

我认为这样做的唯一方法是为所有需要的类型创建非泛型函数。

于 2012-07-30T18:16:37.547 回答
1

编辑:添加到C# 7.3的unmanaged 约束

在这一点上有点晚了,但随着 C# 7.3 的加入,unmanaged类型约束被添加了。

使用非托管类型约束,您可以使用泛型指针 ( T*) 等,前提是传入的类型是非托管的。

我测试了您提供的通用方法,它现在可以工作了。此外,您可以扩展它以返回一个数组,如下所示:

public static unsafe T[] ReadAsArray<T>(this Stream stream) where T : unmanaged
{
    var length = stream.Length;
    var returnArray = new T[length];

    for (var i = 0; i < length; i++)
    {
        int bytesToRead = sizeof(T); // no longer throws error
        byte[] buffer = new byte[bytesToRead];
        if (bytesToRead != stream.Read(buffer, 0, bytesToRead))
        {
            throw new Exception();
        }
        fixed (byte* byteArray = buffer)
        {
            T typeSingle = *(T*)byteArray; // no longer throws error
            returnArray[i] = typeSingle;
        }
    }

    return returnArray;
}

您可以使用以下代码调用它,该代码将打印文件的内容:

using (var sourceStream = File.Open(filename, FileMode.Open))
{
    var byteArray = sourceStream.ReadAsArray<byte>();
    Console.Write(new string(byteArray.Select(b => (char)b).ToArray()));
}
于 2018-03-22T17:50:03.583 回答