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

別の答えがバイナリシリアル化を示唆しているのがわかります。私は個人的に、そのような「不透明な」シリアル化スキームには熱心ではありません。他のプラットフォームに移植できるという意味で、データに何が含まれるのかを正確に知りたいです。

ただし、現在のスキームでは区切り文字が指定されていないことを指摘しておきます。たとえば、2つの文字列がある場合、一方が停止し、もう一方が開始した場所がわかりません。また、タイプ情報を保存しません-それは問題ないかもしれませんが、そうではないかもしれません。通常、可変長の問題の方が重要です。のような長さプレフィックススキームの使用を検討することもできますBinaryWriter。確かに、BinaryWriter一般的にはもっと簡単な解決策かもしれません。デリゲートのマップを引き続き作成したい場合は、デリゲートにBinaryWriterと値をとるアクションを作成します。次に、リフレクション、またはハードコードされた呼び出しのリストによってマップを作成できます。

次に、BinaryWriterラッピングを初期化し、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();

それに加えて、車輪の再発明を避けたい場合は、GoogleProtocolBuffersのようなかなり優れたシリアル化フレームワークがいくつかあります。

于 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 に答える