Domanda

Dato un oggetto FieldInfo e un oggetto, ho bisogno di ottenere la rappresentazione dei byte effettivi del campo. So che il campo è int, Int32, uint, short ecc.

Come posso ottenere la rappresentazione reale del byte? BinaryFormatter.Serialize non aiuta, poiché mi darà più informazioni di quelle di cui ho bisogno (registra anche il nome del tipo ecc.). La classe Marshal non sembra avere strutture per usare l'array di byte (ma forse mi manca qualcosa).

Grazie

È stato utile?

Soluzione

Puoi anche provare un codice come il seguente se ciò che desideri effettivamente è trasferire strutture come array di byte:

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

Questo converte l'oggetto valore nell'array di byte rawdata. Ho preso questo dal codice che ho scritto in precedenza e potrebbe essere necessario adattarlo alle tue esigenze per farlo funzionare davvero. L'ho usato per la comunicazione con alcuni hardware con strutture definite dall'utente, ma dovrebbe funzionare anche per i tipi integrati (dopo tutto, sono strutture, no?)

Per allineare correttamente i membri della struttura, utilizzare l'attributo StructLayout per specificare l'allineamento a un byte:

[StructLayout(LayoutKind.Sequential, Pack = 1)]

Quindi utilizza l'attributo MarshalAs come necessario per i campi, ad es. per array inline:

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
byte[] _state;

Il codice per recuperare la struttura dall'array di byte è qualcosa del genere:

public T GetValue<T>()
{
    GCHandle handle = GCHandle.Alloc(RawValue, GCHandleType.Pinned);
    T structure = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), 
                      typeof(T));
    handle.Free();
    return structure;
}

Ovviamente dovrai conoscere il tipo che vuoi che funzioni.

Nota che questo non gestirà l'endianità per se stesso. Nel mio progetto, la maggior parte dei campi erano costituiti da un solo byte, quindi non importava, ma per i pochi campi in cui lo faceva, rendevo i campi privati ??e aggiungevo proprietà pubbliche che si sarebbero occupate dell'endianness ( il link di Jon Skeet da un commento alla sua risposta può aiutarti, ho scritto alcune funzioni di utilità per questo poiché ne avevo solo bisogno pochi).

Quando ne avevo bisogno, ho creato una classe Message che memorizzava il valore non elaborato (da qui il metodo GetValue, il codice in alto è in realtà il corpo di un metodo SetValue) e aveva un metodo pratico utile per ottenere il valore formattato ecc.

Altri suggerimenti

Usa BitConverter.GetBytes ()

Dovrai prima convertire il valore nel suo tipo nativo, quindi usa BitConverter per ottenere i byte:

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 ....

Intendi la rappresentazione in memoria definitiva? BitConverter.GetBytes (con un sovraccarico opportunamente scelto dalla riflessione) restituirà una rappresentazione di byte, ma non necessariamente ciò che è attualmente in memoria.

Forse se fornisci ulteriori informazioni sul perché lo desideri, saremo in grado di aiutarti meglio.

EDIT: dovrei aggiungere che in ogni caso ragionevole a cui riesco a pensare, BitConverter ti ti darà la stessa rappresentazione della memoria - ma potrebbero esserci situazioni strane che coinvolgono endianness e possibilmente strane architetture con differenti rappresentazioni in virgola mobile che potrebbero dare risultati strani.

MODIFICA: ecco un programma di esempio completo che dimostra come procedere:

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));
        }        
    }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top