2

FieldInfo オブジェクトとオブジェクトが与えられた場合、フィールドの実際のバイト表現を取得する必要があります。int,Int32,uint,shortフィールドがどちらかなどであることを知っています。

実際のバイト表現を取得するにはどうすればよいですか? BinaryFormatter.Serialize は役に立ちません。必要以上の情報が得られるからです (型名なども記録されます)。このMarshalクラスには、バイト配列を使用する機能がないようです (ただし、何か不足している可能性があります)。

ありがとう

4

3 に答える 3

7

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 ....
于 2008-10-22T13:32:08.370 に答える
3

構造体をバイト配列として転送することが実際に必要な場合は、次のようなコードを試すこともできます。

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

これは、指定されたオブジェクトをバイト配列 rawdata に変換します。これは以前に書いたコードから取ったもので、実際に機能させるには、ニーズに合わせて調整する必要がある場合があります。ユーザー定義の構造体を持つハードウェアとの通信に使用しましたが、組み込み型でも機能するはずです (結局のところ、それらは構造体ですよね?)。

構造体メンバーを適切に整列させるには、StructLayout 属性を使用して one-byte-alignment を指定します。

[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 メソッドの本体です)、フォーマットされた値を取得するための便利なメソッドをいくつか用意しました。

于 2008-10-22T13:41:06.760 に答える
2

決定的なメモリ内表現のことですか? BitConverter.GetBytes (リフレクションによって適切に選択されたオーバーロードを使用) はバイト表現を返しますが現在メモリ内にあるものとは限りません。

なぜこれが必要なのかを詳しく教えていただければ、より適切なサポートができるでしょう。

編集:私が考えることができる賢明なケースでは、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));
        }        
    }
}
于 2008-10-22T13:32:53.873 に答える