从字节数组中泛化反序列化

时间:2017-05-10 18:53:31

标签: c# generics

我正在解析包含以固定格式存储的不同类型值的字节数组。例如,前4个字节可以是包含数组大小的int -  让我们说双打数组,所以接下来的8个字节代表一个双 - 数组的第一个元素等。它理论上可以包含其他类型的值,但是让我们说我们只能有 bool,int,uint,short,ushort,long,ulong,float,double和这些中的每一个的数组。简单的方法:

public class FixedFormatParser
{
    private byte[] _Contents;
    private int _CurrentPos = 0;
    public FixedFormatParser(byte[] contents)
    {
        _Contents = contents;
    }

    bool ReadBool()
    {
        bool res = BitConverter.ToBoolean(_Contents, _CurrentPos);
        _CurrentPos += sizeof(bool);
        return res;
    }

    int ReadInt()
    {
        int res = BitConverter.ToInt32(_Contents, _CurrentPos);
        _CurrentPos += sizeof(int);
        return res;
    }

    // etc. for uint, short, ushort, long, ulong, float, double

    int[] ReadIntArray()
    {
        int size = ReadInt();

        if (size == 0)
            return null;

        int[] res = new int[size];

        for (int i = 0; i < size; i++)
            res[i] = ReadInt();

        return res;
    }

    // etc. for bool, uint, short, ushort, long, ulong, float, double
}

我显然可以编写18种方法来涵盖每种情况,但似乎应该有一种方法来概括这一点。

bool val = Read<bool>(); 
long[] arr = ReadArray<long>(); // or ReadArray(Read<long>); 

显然,除了允许这种语法的18种方法之外,我并不意味着编写2个包装器。语法并不重要,代码重复是个问题。另一个考虑因素是性能。理想情况下,不会有任何(或很多)性能损失。感谢。

更新

关于其他可能重复的问题。我不同意,因为他们都没有解决我所追求的特定概括,但一个非常接近: 第一个回答 C# Reading Byte Array 描述了包装BinaryReader。这将涵盖18种方法中的9种。所以问题的一半得到了解决。我仍然需要编写所有各种数组读取。

public class FixedFormatParser2 : BinaryReader
{
    public FixedFormatParser2(byte[] input) : base(new MemoryStream(input))
    {
    }

    public override string ReadString()
    {
        //            
    }

    public double[] ReadDoubleArray()
    {
        int size = ReadInt32();

        if (size == 0)
            return null;

        double[] res = new double[size];

        for (int i = 0; i < size; i++)
            res[i] = ReadDouble();

        return res;
    }
}

如何为每种类型编写单独的ReadXXXArray?

我最近得到了它:

    public void WriteCountedArray(dynamic[] input) 
    {
        if (input == null || input.Length == 0)
            Write((int)0);
        else
        {
            Write(input.Length);
            foreach (dynamic val in input)
                Write(val);
        }
    }

这编译但是调用它既麻烦又昂贵:

        using (FixedFormatWriter writer = new FixedFormatWriter())
        {
            double[] array = new double[3];
            // ... assign values
            writer.WriteCountedArray(array.Select(x=>(dynamic)x).ToArray());

1 个答案:

答案 0 :(得分:0)

我喜欢这样做

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Xml;
using System.Xml.Serialization;
using System.IO;


namespace ConsoleApplication50
{
    class Program
    {

        static void Main(string[] args)
        {
            new Format();

        }
    }
    public class Format
    {
        public enum TYPES
        {
            INT,
            INT16,
            LONG
        }

        public static List<Format> format = new List<Format>() {
            new Format() { name = "AccountNumber", _type = TYPES.INT ,numberOfBytes = 4},
            new Format() { name = "Age", _type = TYPES.INT16 ,numberOfBytes = 2},
            new Format() { name = "AccountNumber", _type = TYPES.LONG ,numberOfBytes = 8}
        };

        public Dictionary<string, object> dict = new Dictionary<string, object>();

        public string name { get; set; }
        public TYPES _type { get; set;  }
        public int numberOfBytes { get; set; }

        public Format() { }

        public Format(byte[] contents)
        {
            MemoryStream stream = new MemoryStream(contents);
            BinaryReader reader = new BinaryReader(stream);

            foreach (Format item in format)
            {
                switch (item._type)
                {
                    case TYPES.INT16 :
                        dict.Add(item.name, reader.ReadInt16());
                        break;

                    case TYPES.INT:
                        dict.Add(item.name, reader.ReadInt32());
                        break;

                    case TYPES.LONG:
                        dict.Add(item.name, reader.ReadInt64());
                        break;

                }
            }
        }
    }

}