Convert an array of different value types to a byte array

后端 未结 3 739
花落未央
花落未央 2020-12-21 22:41

This is what I\'ve come up with so far, but it doesn\'t seem very optimal, any ideas on better approaches?

public void ToBytes(object[] data, byte[] buffer)
         


        
相关标签:
3条回答
  • 2020-12-21 23:16

    Well, you could have a map like this:

    private static readonlyDictionary<Type, Func<object, byte[]>> Converters = 
        new Dictionary<Type, Func<object, byte[]>>()
    {
        { typeof(string), o => Encoding.UTF8.GetBytes((string) o) },
        { typeof(bool), o => BitConverter.GetBytes((bool) o) },
        { typeof(char), o => BitConverter.GetBytes((char) o) },
        ...
    };
    
    public static void ToBytes(object[] data, byte[] buffer)
    {
        int offset = 0;
    
        foreach (object obj in data)
        {
            if (obj == null)
            {
                // Or do whatever you want
                throw new ArgumentException("Unable to convert null values");
            }
            Func<object, byte[]> converter;
            if (!Converters.TryGetValue(obj.GetType(), out converter))
            {
                throw new ArgumentException("No converter for " + obj.GetType());
            }
    
            byte[] obytes = converter(obj);
            Buffer.BlockCopy(obytes, 0, buffer, offset, obytes.Length);
            offset += obytes.Length;
        }
    }
    

    You're still specifying the converter for each type, but it's a lot more compact than the if/else form.

    There are various other ways of constructing the dictionary, btw. You could do it like this:

    private static readonly Dictionary<Type, Func<object, byte[]>> Converters = 
            new Dictionary<Type, Func<object, byte[]>>();
    
    static WhateverYourTypeIsCalled()
    {
        AddConverter<string>(Encoding.UTF8.GetBytes);
        AddConverter<bool>(BitConverter.GetBytes);
        AddConverter<char>(BitConverter.GetBytes);
    }
    
    static void AddConverter<T>(Func<T, byte[]> converter)
    {
        Converters.Add(typeof(T), x => converter((T) x));
    }
    

    I see another answer has suggested binary serialization. I'm personally not keen on "opaque" serialization schemes like that. I like to know exactly what's going to be in the data in a way that means I can port it to other platforms.

    I would point out, however, that your current scheme doesn't give any sort of delimiter - if you have two strings, you'd have no idea where one stopped and the other started, for example. You also don't store the type information - that may be okay, but it may not be. The variable length issue is usually more important. You might consider using a length-prefix scheme, like the one in BinaryWriter. Indeed, BinaryWriter may well be a simpler solution in general. You'd probably want to still have a map of delegates, but make them actions taking a BinaryWriter and a value. You could then build the map by reflection, or just a hardcoded list of calls.

    Then you'd just initialize a BinaryWriter wrapping a MemoryStream, write each value to it appropriately, then call ToArray on the MemoryStream to get the results.

    0 讨论(0)
  • 2020-12-21 23:22

    Probably, you should consider using BinaryFormatter instead:

    var formatter = new BinaryFormatter();
    var stream = new MemoryStream();
    formatter.Serialize(stream, obj);
    byte[] result = stream.ToArray();
    

    Beside that, there are some pretty good serialization frameworks like Google Protocol Buffers if you want to avoid reinventing the wheel.

    0 讨论(0)
  • 2020-12-21 23:24

    You can use a StreamWriter to write to a memory stream and use its buffer:

      {
                   byte[] result;
                using (MemoryStream stream = new MemoryStream())
                {
                    StreamWriter writer = new StreamWriter(stream);
                    writer.WriteLine("test");
                    writer.WriteLine(12);
                    writer.WriteLine(true);
    
                    writer.Flush();
    
                    result = stream.GetBuffer();
                }
    
                using(MemoryStream stream=new MemoryStream(result))
                {
                    StreamReader reader = new StreamReader(stream);
                   while(! reader.EndOfStream)
                     Console.WriteLine(reader.ReadLine());
                   }
                }
    
    0 讨论(0)
提交回复
热议问题