C#でInt / short / byte構造のバイト表現を取得する
-
03-07-2019 - |
質問
FieldInfoオブジェクトとオブジェクトを指定すると、フィールドの実際のバイト表現を取得する必要があります。フィールドが int、Int32、uint、short
などのいずれかであることを知っています。
実際のバイト表現を取得するにはどうすればよいですか? BinaryFormatter.Serializeは、必要以上の情報を提供してくれるので役に立ちません(タイプ名なども記録します)。 Marshal
クラスには、バイト配列を使用する機能がないようです(ただし、何か不足している可能性があります)。
ありがとう
解決
構造をバイト配列として転送したい場合は、次のようなコードを試すこともできます。
int rawsize = Marshal.SizeOf(value);
byte[] rawdata = new byte[rawsize];
GCHandle handle = GCHandle.Alloc(rawdata, GCHandleType.Pinned);
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
handle.Free();
これは、指定されたオブジェクトの value をバイト配列rawdataに変換します。私は以前に書いたコードからこれを取りましたが、実際に機能させるには、ニーズに合わせて調整する必要があるかもしれません。ユーザー定義の構造を持つ一部のハードウェアとの通信に使用しましたが、組み込み型でも機能するはずです(結局、構造ですよね?)
構造体メンバーを適切に配置するには、StructLayout属性を使用して1バイトの配置を指定します。
[StructLayout(LayoutKind.Sequential, Pack = 1)]
そして、フィールドの必要に応じてMarshalAs属性を使用します。インライン配列の場合:
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
byte[] _state;
バイト配列から構造を取得するコードは次のようなものです:
public T GetValue<T>()
{
GCHandle handle = GCHandle.Alloc(RawValue, GCHandleType.Pinned);
T structure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(),
typeof(T));
handle.Free();
return structure;
}
もちろん、これが機能するために必要なタイプを知る必要があります。
これはそれ自体のエンディアンを処理しないことに注意してください。私のプロジェクトでは、ほとんどのフィールドは1バイトのみでしたので、それは問題ではありませんでしたが、いくつかのフィールドについては、フィールドをプライベートにし、エンディアンを処理するパブリックプロパティを追加しました( Jon Skeetのコメントから回答へのリンクが役立つ場合があります。少数)。
これが必要になったとき、生の値を格納するMessageクラスを作成しました(したがって、GetValueメソッドです。上部のコードは実際にはSetValueメソッドの本体です)。など。
他のヒント
BitConverter.GetBytes()を使用
BitConverterを使用してバイトを取得する前に、最初に値をネイティブ型に変換する必要があります。
byte[] Bytes;
if (valType == typeof(int))
{
int intVal = (int) GetFieldValue(....);
Bytes = BitConverter.GetBytes(intVval);
}
else if (valType == typeof(long))
{
int lngVal = (long) GetFieldValue(....);
Bytes = BitConverter.GetBytes(lngVal);
} else ....
最終的なメモリ内表現を意味しますか? BitConverter.GetBytes(リフレクションによって適切に選択されたオーバーロードを使用)は、 a バイト表現を返しますが、必ずしも現在メモリにあるものとは限りません。
おそらく、これが必要な理由についてもっと情報を提供していただければ、私たちはあなたをよりよく手助けできるでしょう。
編集:私が考えることができるどんな賢明なケースでも、BitConverterはメモリ内と同じ表現をあなたに与えます-しかし、エンディアンネスとおそらく異なる奇妙なアーキテクチャを含む奇妙な状況があるかもしれません奇妙な結果をもたらす可能性のある浮動小数点表現。
編集:これを実行する方法を示す完全なサンプルプログラムを次に示します。
using System;
using System.Reflection;
public class Test
{
public int x = 300;
static void Main()
{
Test instance = new Test();
FieldInfo field = typeof(Test).GetField("x");
MethodInfo converter = typeof(BitConverter).GetMethod("GetBytes",
new Type[] {field.FieldType});
if (converter == null)
{
Console.WriteLine("No BitConverter.GetBytes method found for type "
+ field.FieldType);
}
else
{
byte[] bytes = (byte[]) converter.Invoke(null,
new object[] {field.GetValue(instance) });
Console.WriteLine("Byte array: {0}", BitConverter.ToString(bytes));
}
}
}