2011-01-09 4 views
2

以下の.NETタイプ観察:私は、単一のバイト配列にXのN要素の配列を変換する必要があり、その逆も効率的かつコードがバイナリシリアライゼーションを忘れる意味(互換シルバーでなければならないSilverlight互換の方法で.NETの中でプリミティブ型の束をバイト配列に効率的に変換する方法は?

public class X 
{ 
    public DateTime Timestamp {get;set;} 
    public double Value {get;set;} 
    public double Min {get;set;} 
    public double Max {get;set;} 
} 

を、効率的かどうか)。

私のソリューションは、次のとおりです。

public void GetState(SerializationInfo info) 
{ 
    var stream = new MemoryStream(); 
    var buf = BitConverter.GetBytes(Count); 
    stream.Write(buf, 0, buf.Length); 
    foreach (var item in this) 
    { 
    buf = BitConverter.GetBytes(item.Timestamp.Ticks); 
    stream.Write(buf, 0, buf.Length); 
    buf = BitConverter.GetBytes(item.Value); 
    stream.Write(buf, 0, buf.Length); 
    buf = BitConverter.GetBytes(item.Min); 
    stream.Write(buf, 0, buf.Length); 
    buf = BitConverter.GetBytes(item.Max); 
    stream.Write(buf, 0, buf.Length); 
    } 
    info.AddValue("Data", stream.ToArray()); 
} 
public void SetState(SerializationInfo info) 
{ 
    var data = info.GetValue<byte[]>("Data"); 
    int count = BitConverter.ToInt32(data, 0); 
    Capacity = count; 
    int offset = sizeof(int); 
    while (count-- > 0) 
    { 
    Add(new ExtendedNormalizedSample(
     new DateTime(BitConverter.ToInt64(data, offset)), 
     BitConverter.ToDouble(data, offset += sizeof(long)), 
     BitConverter.ToDouble(data, offset += sizeof(double)), 
     BitConverter.ToDouble(data, offset += sizeof(double)))); 
    offset += sizeof(double); 
    } 
} 

(SerializationInfoにもの無視 - 質問には無関係)私の解決策は、中に作成されたバイト[]配列の存在量は約私は好きではないものを、とにかく

をシリアライゼーション。つまり、BitConverter.GetBytesを呼び出すたびに新しいバイト配列が返されますが、新しいバイト配列を作成するのは.NETでは安いですが、以前のC++開発者の場合は毎回新しいバイト配列を使用するのはひどい浪費に見えますが、 1バイトの配列は再利用できます。

もっと良い解決方法を提案できる人はいますか(覚えておいてください、Silverlightと互換性があるので、安全でないコードを提案しないでください)。

ありがとうございました。

+0

サイドノート:protobuf-netのような別のシリアライザも検討したいと思うかもしれません。あなたのエンコーディングをすべて行う必要はありません。(v2の出荷時には、SLに役立ちます)、そして非常に小さな出力です。プラス:無料。 –

+0

私は今すぐ急変する必要がありますが、私は常にprotobuf-netを念頭に置いています。 – mark

答えて

2

DateTimeTicksは、シフト演算などを経由して整数として符号化することができfloat - あなたかもしれシフト操作でintをエンコード、その後intのためにスワップする労働組合を使用してみてください、と:

[StructLayout(LayoutKind.Explicit)] 
struct MyUnion 
{ 
    [FieldOffset(0)] 
    private int i; 
    [FieldOffset(0)] 
    private float f; 

    public static int ToInt32(float value) { 
     MyUnion u = new MyUnion(); 
     u.f = value; 
     return u.i; 
    } 
    public static float ToSingle(int value) { 
     MyUnion u = new MyUnion(); 
     u.i = value; 
     return u.f; 
    } 
} 

次に、既存のStreamまたはbyte[]をお持ちの場合は、選択したエンディアンに応じてエンコードできます。

int iValue = MyUnion.ToInt32(fValue); 


int offset = ...; 
... 
buffer[offset++] = (byte)iValue; 
buffer[offset++] = (byte)(iValue >> 8); 
buffer[offset++] = (byte)(iValue >> 16); 
buffer[offset++] = (byte)(iValue >> 24); 
+0

しかし、私はダブル、浮動小数点を持っていません。だから、intよりむしろ長くなければならない。 – mark

+0

私は、それは問題ではないと思います - プリンシパルは同じままです。ありがとう。 – mark

+0

@マーク - 確かに;その場合の 'long'のsubst –

関連する問題