-1

I am parsing a byte array containing different type values stored in a fixed format. For example first 4 bytes could be an int containing size of an array - let's say the array of doubles so next 8 bytes represent a double - the first element of the array etc. It could in theory contain values of other types, but let's say we can only have bool,int,uint,short,ushort,long,ulong,float,double and arrays of each of these. Simple approach:

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
}

I can obviously write 18 methods to cover each case, but seems like there should be a way to generalize this.

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

Obviously I don't mean write 2 wrappers in addition to the 18 methods to allow for this syntax. The syntax is not important, the code duplication is the issue. Another consideration is the performance. Ideally there would not be any (or much) of a performance hit. Thanks.

Update:

Regarding other questions that are supposedly duplicates. I disagree as none of them addressed the particular generalization I am after, but one came pretty close: First answer in C# Reading Byte Array described wrapping BinaryReader. This would cover 9 of the 18 methods. So half of the problem is addressed. I still would need to write all of the various array reads.

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;
    }
}

How do I not write a separate ReadXXXArray for each of the types?

Nearest I got to it:

    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);
        }
    }

This compiles but calling it is cumbersome and expensive :

        using (FixedFormatWriter writer = new FixedFormatWriter())
        {
            double[] array = new double[3];
            // ... assign values
            writer.WriteCountedArray(array.Select(x=>(dynamic)x).ToArray());
Community
  • 1
  • 1
ILIA BROUDNO
  • 1,539
  • 17
  • 24
  • 2
    I haven't tried to do what you're doing, but [is this question helpful](http://stackoverflow.com/q/1455581/120955)? – StriplingWarrior May 10 '17 at 18:59
  • StriplingWarrior - I did bother to get your suggestion to work. A better link to a working example is http://stackoverflow.com/questions/2623761/marshal-ptrtostructure-and-back-again-and-generic-solution-for-endianness-swap the problem with this approach is that it is expensive and cumbersome enough that I would prefer code duplication. But yes it does technically do what I asked. – ILIA BROUDNO May 11 '17 at 18:05

1 Answers1

0

I like doing like this

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;

                }
            }
        }
    }

}
jdweng
  • 33,250
  • 2
  • 15
  • 20