代码之家  ›  专栏  ›  技术社区  ›  willeM_ Van Onsem

将字节数组转换为C中类型未知的基元类型数组#

  •  5
  • willeM_ Van Onsem  · 技术社区  · 14 年前

    我有以下问题。我有一个字节数组,我想把它转换成一个基元类型的数组。但我不知道是哪种类型。(这是一个类型数组)。因此,我需要一个对象数组。

    当然,我可以在类型上使用开关(它们的数量有限),但我想知道是否有更好的解决方案。

    例子:

    byte[] byteData = new byte[] {0xa0,0x14,0x72,0xbf,0x72,0x3c,0x21}
    Type[] types = new Type[] {typeof(int),typeof(short),typeof(sbyte)};
    
    //some algorithm
    
    object[] primitiveData = {...};
    //this array contains an the following elements
    //an int converted from 0xa0,0x14,0x72,0xbf
    //a short converted from 0x72, 0x3c
    //a sbyte converted from 0x21
    

    这有算法吗?还是我应该使用开关

    5 回复  |  直到 12 年前
        1
  •  2
  •   Mikael Svenson    14 年前

    此代码使用unsafe获取指向字节数组缓冲区的指针,但这不应该是问题。

    [编辑-注释后更改的代码]

    byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 };
    Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) };
    
    object[] result = new object[types.Length];
    unsafe
    {
        fixed (byte* p = byteData)
        {
            var localPtr = p;
            for (int i = 0; i < types.Length; i++)
            {
                result[i] = Marshal.PtrToStructure((IntPtr)localPtr, types[i]);
                localPtr += Marshal.SizeOf(types[i]);
            }
        }
    }
    
        2
  •  3
  •   abatishchev Karl Johan    14 年前

    我的想法是:

    object[] primitiveData = new object[byteData.Lenght];
    for (int i = 0; i < bytesData.Lenght; i++)
    {
         primitiveData[i] = Converter.ChangeType(bytesData[i], types[i]);
    }
    

    object[] primitiveData = new object[bytDate.Lenght];
    for (int i = 0; i < bytesDate.Lenght; i++)
    {
         Type t = types[i];
         if (t == typeof(int))
         {
              primitiveData[i] = Convert.ToInt32(bytesDate[i]);
         }
         else if (t == typeof(short))
         {
              primitiveData[i] = Convert.ToInt16(bytesDate[i]);
         }
         ..
    }
    

    var dic = new Dictionary<Type, Func<byte, object>>
    {
        { typeof(int), b => Convert.ToInt32(b) },
        { typeof(short), b => Convert.ToInt16(b) },
        ...
    };
    
    byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 };
    Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) };
    
    List<object> list = new List<object>(primitiveData.Length);
    for (int i = 0; i < primitiveData.Length; i++)
    {
         Byte b = byteData[i];
         Type t = types[i];
         Func<byte, object> func = dic[t];
         list.Add(func(b));
    }
    object[] primitiveData = list.ToArray();
    

    byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 };
    // delegates to converters instead of just appropriate types
    Func<byte, object>[] funcs = new Func<byte, object>[]
    {
         b => Convert.ToInt32(b),
         b => Convert.ToInt16(b),
         b => Convert.ToSByte(b)
    };
    
    List<object> list = new List<object>(primitiveData.Length);
    for (int i = 0; i < primitiveData.Length; i++)
    {
         Byte b = byteData[i];
         Func<byte, object> func = funcs[i];
         list.Add(func(b));
    }
    object[] primitiveData = list.ToArray();
    

    注意,上面所有的解决方案都假定 对称性 之间 byteData types .

    否则,您必须准备一个包含非对称数组索引的对称数组:

    byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 };
    Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) }; // asymmetric 
    int[] indexes = new int[] { 0, 0, 0, 0, 1, 2 }; // symmetric 
    
        3
  •  1
  •   Darin Dimitrov    14 年前

    你可以使用 BinaryReader :

    public static IEnumerable<object> ConvertToObjects(byte[] byteData, Type[] types)
    {
        using (var stream = new MemoryStream(byteData))
        using (var reader = new BinaryReader(stream))
        {
            foreach (var type in types)
            {
                if (type == typeof(short))
                {
                    yield return reader.ReadInt16();
                }
                else if (type == typeof(int))
                {
                    yield return reader.ReadInt32();
                }
                else if (type == typeof(sbyte))
                {
                    yield return reader.ReadSByte();
                }
                // ... other types
                else
                {
                    throw new NotSupportedException(string.Format("{0} is not supported", type));
                }
            }
        }
    }
    

    然后:

    byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 };
    Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) };
    object[] result = ConvertToObjects(byteData, types).ToArray();
    
        4
  •  0
  •   Cipi    14 年前

    有点脏,但它起作用… sp 用于指向从中的下一个位置读取 byteData ,我想可以用其他方法检查类型…但这只是一个想法。所以如果你不喜欢,请不要-1我。=)

            byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 };
            Type[] types = new Type[] {typeof(int),typeof(short),typeof(sbyte)};
    
            object[] primitiveData = new object[types.Length];
            int sp = 0;
    
            for(int i=0; i<types.Length; i++)
            {
    
                string s = types[i].FullName;
                switch(types[i].FullName)
                {
                    case "System.Int32":{
                        primitiveData[i] = BitConverter.ToInt32(byteData, sp);
                        sp += 4;
                    }break;
                    case "System.Int16":
                        {
                        primitiveData[i] = BitConverter.ToInt16(byteData, sp);
                        sp += 2;
                    }break;
                    case "System.SByte":
                        {
                        primitiveData[i] = (sbyte)byteData[sp];
                        sp += 1;
                    }break;
    
                }
            }
    
        5
  •  0
  •   Tim Cooper    13 年前

    可以使用反射创建数组并填充它们。(请注意,由于sbyte的数据错误而导致的错误处理程序):

      [TestMethod]
      public void MyTestMethod() {
         byte[] byteData = new byte[] { 0xa0, 0x14, 0x72, 0xbf, 0x72, 0x3c, 0x21 };
         Type[] types = new Type[] { typeof(int), typeof(short), typeof(sbyte) };
    
         List<Array> result = new List<Array>();
    
         foreach (var type in types) {
            Type arrayType = type.MakeArrayType();
            ConstructorInfo ctor = arrayType.GetConstructor(new Type[] { typeof(int) });
            Array array = (Array)ctor.Invoke(new object[] { byteData.Length });
    
            for (int i = 0; i < byteData.Length; i++) {
               byte b = byteData[i];
               try {
                  array.SetValue(Convert.ChangeType(b, type), i);
               } catch {
                  Console.WriteLine("Error with type {0} and value {1}", type, b);
               }
            }
    
            result.Add(array);
         }
    
         // -------------------
         // show result
         foreach (var array in result) {
            Console.WriteLine(array.GetType());
            foreach (var item in array) {
               Console.WriteLine("   {0}", item);
            }
         }
      }