2011-12-15 32 views
2

私は価値の構造体の型のSystem.Array、このようなものがあります:値構造体の配列をバイトに変換するには?

public value struct Position 
{ 
    int timestamp; 
    float x; 
    float y; 
} 

Position[] positions = new Position[1000 * 1000]; 

私は値で配列を初期化した後、どのように私は、一度に1つのアイテムをシリアル化せずに、それのコンテンツのbyte[]を得ることができますか?

私はpin_ptrを使用して配列の内容へのポインタを取得し、そこからデータをコピーします。 C#でこれを行うことはできますか?

EDIT:シリアルデータなしで、C構造体のように、生データをディスクに書き込む必要があります。

この質問にC#として広範な露出を付けましたが、IronPythonからデータをシリアル化しようとしています。つまり、unsafe C#の機能は使用できません。

+1

Convert.GetBytes()は動作しませんか? – Default

+0

重複:http://stackoverflow.com/questions/1068541/how-to-convert-a-value-type-to-byte-in-c – Kugel

+0

@Default:もしあなたが 'BitConverter.GetBytes'を指しているなら、いいえ、それは動作しません。内部で1バイトの 'byte []'を返します – Meh

答えて

1

ここでは、安全でないコードを必要としない方法があります:

[forループを削除してシングルパスでコピーするように更新]

private static byte[] StructureToByteArray(Position[] posArray) 
{ 
    if (posArray == null || posArray.Length == 0) 
    { 
     return new byte[0]; 
    } 

    var lenOfObject = Marshal.SizeOf(typeof(Position)); 
    var len = lenOfObject * posArray.Length; 
    var arr = new byte[len]; 

    var handle = GCHandle.Alloc(posArray, GCHandleType.Pinned); 
    try 
    { 
     var ptr = handle.AddrOfPinnedObject(); 
     Marshal.Copy(ptr, arr, 0, len); 
    } 
    finally 
    { 
     handle.Free(); 
    } 

    return arr; 
} 
+0

安全でない答えと同じ質問:このアプローチを使用している場合は、 'StructLayout'属性を' Sequential'または 'Explicit'の' LayoutKind'で 'Position'構造体に適用することをお勧めしますか?問題にならない? –

+0

'LayoutKind.Sequential'を指定することをお勧めします。構造体はinteropのために頻繁に使用されるので、C#/ VB.NETコンパイラ(とおそらく他のもの)のデフォルトですが、それが真実であるという保証はありません。 –

+0

これは各項目を通過します。私はそれを避けたい。 – Meh

2

多分これが役立ちます。

[Serializable()] 
    public struct Position 
    { 
     int timestamp; 
     float x; 
     float y; 
    } 


    static void Main(string[] args) 
    { 
     var positions = new Position[1000 * 1000]; 
     GetBytes(positions); 
    } 
    private static byte[] GetBytes(object obj) 
    { 
     using (var memoryStream = new System.IO.MemoryStream()) 
     { 
      var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 
      binaryFormatter.Serialize(memoryStream, obj); 
      return memoryStream.ToArray(); 
     } 
    } 
+0

'Serialization'フォーマッタが生データを返すとは思いません。 – Meh

+0

このアプローチではバイト配列が得られますが、コーディングにはほとんど手間がかかりませんので、これは完全に正しい答えだと思います。結果として得られるバイト配列は、デシリアライズに使用されるいくつかの型情報を含んでいるため、できるだけ小さくありません。これが自分の必要性に合っているかどうかは、個人によって異なります。 –

+0

私は、標準パッケージを使用するとC#が安全でないコードを使用する方が良いと思います。また、オブジェクトをシリアライズするときに、型情報を保存する必要があるのは事実だと思います。したがって、バイト配列が大きくなる可能性がありますが、標準的な解決策がより好ましいと思います – Arion

1

を、私は、これは危険なC#のコードを使用してpin_ptr C++/CLIと同等であると考えている:

public static unsafe byte[] GetBytes(Position[] positions) 
    { 
     byte[] result = new byte[positions.Length * Marshal.SizeOf(typeof(Position))]; 
     fixed (Position* ptr = &positions[0]) 
     { 
      Marshal.Copy((IntPtr)ptr, result, 0, result.Length); 
     } 
     return result; 
    } 
+0

このアプローチを確実に使用するには、StructLayout属性をSequentialまたはExplicitのLayoutKindと共にPosition構造体に適用する必要がありますか?ただ疑問に思う。 –

+0

ありがとうございますが、私は安全ではありません。私はその理由を説明に更新しました。 – Meh

+0

@Dr。 WilyのApprenticeでは、特定のバイナリレイアウトを期待しているアンマネージコードとの相互運用を試みる場合は、Explicitレイアウトを使用することをお勧めします。私は自動レイアウト配置の保証がどれくらい強固かはわかりません。 –

関連する問題