一般的な BitConverter のようなメソッドですか?
-
12-09-2019 - |
質問
最近、バイト配列からデータ型を読み取るための汎用メソッドを作成する必要がある状況に遭遇しました。
次のクラスを作成しました。
public class DataStream
{
public int Offset { get; set; }
public byte[] Data { get; set; }
public T Read<T>() where T : struct
{
unsafe
{
int dataLen = Marshal.SizeOf( typeof( T ) );
IntPtr dataBlock = Marshal.AllocHGlobal( dataLen );
Marshal.Copy( Data, Offset, dataBlock, dataLen );
T type = *( ( T* )dataBlock.ToPointer() );
Marshal.FreeHGlobal( dataBlock );
Offset += dataLen;
return type;
}
}
}
さて、割り当て解除の問題はさておき、このコードはコンパイルされず、次のメッセージが表示されます。
Cannot take the address of, get the size of, or declare a pointer to a managed type ('T')
に基づいて上記の操作を実行できるはずなので、これは奇妙に思えます。 where T : struct
メソッドに対する制約。
このコードがひどく間違っている場合、一連のバイトを取得して ' にキャストする簡単な方法はありますか?T
' タイプ?
ありがとう!
解決
ポインター操作でこれを行う代わりに、使用するようにコードを切り替える必要があります。 Mashal.PtrToStructure. 。このメソッドは、このシナリオ向けに特別に設計されています。
他のヒント
て回答していたら、ついてお話ししましょう"なぜ"オリジナルのコードは動作しなかったです。
れようとするのは不思議で対応することができるでしょうかを、上記業務に基づく場:struct制約の研究"に関するお問合せ
をしなければいけません。できる原へのポインタ ポ種類.これは次のように定義されていますのC#言語仕様(18.2):
参考文献とは異なります(参照)、ポインタなどの追跡では、ガベージコレクタによって、ガベージコレクタに関する知識が全くないのポインタのデータです。このためのポインタが許可されていないポイント参照、構造体を含む参考文献のリファレントタイプのポインタでなければな ポ-タイプ.An ポ-タイプ はう機会を設けていきたいと思い参照型を含まない参照型の分野のレベルの営巣.つまり、 ポ-タイプ は、次のいずれかになります:
sbyte
,byte
,short
,ushort
,int
,uint
,long
,ulong
,char
,float
,double
,decimal
, やbool
.- 他の enumタイプ.
- 他の ポインタ型.
- ユーザー定義 structタイプ を含む分野 ポ-種類 だけます。
いのでかなりの数の制限は、一般的方法 T:struct
ませんし、それに適合する特定インスタンス生成、構築しよう T*
ることは違法である。ができると思うのですが、特別な汎用タイプのパラメータの制約をカバーでポリシーの種類は、そのまま、ありませんのCLR.
1つの時点で私はまさにそれを行う方法を説明するこのこの記事を書きましたMarshal.PtrToStructureよりも、多くの倍の速さ。サンプルコードは、ビットストリームから/へのジェネリック型Tをコピーするために、動的コード生成を使用します。
仮:
- 連続または明示的な構造そのものは悪いこと)
- 正しいデータサイズ(べき事前チェックイン&スロー)
unsafe TStruct BytesToStructure<TStruct>(byte[] data) where TStruct : struct
{
fixed (byte* dataPtr = data)
return (TStruct)Marshal.PtrToStructure(new IntPtr(dataPtr), typeof(TStruct));
}
unsafe byte[] StructureToBytes<TStruct>(TStruct st) where TStruct : struct
{
var bytes = new byte[Marshal.SizeOf(st)];
fixed (byte* ptr = bytes) Marshal.StructureToPtr(st, new IntPtr(ptr), true);
return bytes;
}
私は同じことを行うにはしばらく前にこれを書いた: http://www.codeproject.com/Articles/33713/Generic-BinaryReader-and-BinaryWriter-Extensionsする
あなたはしかし、あなたのVisual StudioソリューションにC ++ / CLIのプロジェクトを追加する必要があります。