1

到目前为止,这是我想出的,但似乎不是很理想,关于更好方法的任何想法?

public void ToBytes(object[] data, byte[] buffer)
{
    byte[] obytes;
    int offset = 0;

    foreach (object obj in data)
    {
        if (obj is string)
            obytes = System.Text.Encoding.UTF8.GetBytes(((string)obj));
        else if (obj is bool)
            obytes = BitConverter.GetBytes((bool)obj);
        else if (obj is char)
            obytes = BitConverter.GetBytes((char)obj);
        // And so on for each valuetype

        Buffer.BlockCopy(obytes, 0, buffer, offset, obytes.Length);
        offset += obytes.Length;
    }
}
4

3 回答 3

4

好吧,你可以有这样的地图:

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

您仍在为每种类型指定转换器,但它比 if/else 形式紧凑得多。

顺便说一句,还有其他各种构建字典的方法。你可以这样做:

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

我看到另一个答案建议二进制序列化。我个人并不热衷于这样的“不透明”序列化方案。我想确切地知道数据中的内容,这意味着我可以将其移植到其他平台。

但是,我要指出,您当前的方案没有给出任何类型的分隔符 - 例如,如果您有两个字符串,您将不知道一个在哪里停止而另一个在哪里开始。您也不存储类型信息 - 这可能没问题,但可能不是。可变长度问题通常更为重要。您可以考虑使用长度前缀方案,例如BinaryWriter. 实际上,BinaryWriter一般来说,这很可能是一个更简单的解决方案。您可能仍然希望有一个代表地图,但让他们采取行动采取 aBinaryWriter和价值。然后,您可以通过反射构建地图,或者只是一个硬编码的调用列表。

然后你只需初始化一个BinaryWriter包装 a MemoryStream,将每个值适当地写入它,然后调用ToArrayMemoryStream获取结果。

于 2009-09-06T14:55:10.567 回答
2

可能,您应该考虑BinaryFormatter改用:

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

除此之外,如果您想避免重新发明轮子,还有一些非常好的序列化框架,例如Google Protocol Buffers 。

于 2009-09-06T14:53:18.653 回答
0

您可以使用 StreamWriter 写入内存流并使用其缓冲区:

  {
               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());
               }
            }
于 2009-09-06T16:11:05.767 回答