Question

Étant donné un objet FieldInfo et un objet, je dois obtenir la représentation en octets réelle du champ. Je sais que le champ est soit int, Int32, uint, short , etc.

Comment puis-je obtenir la représentation en octets réelle? BinaryFormatter.Serialize ne va pas aider, car il me donnera plus d'informations que nécessaire (il enregistre également le nom du type, etc.). La classe Marshal ne semble pas disposer d'installations pour utiliser un tableau d'octets (mais il se peut que quelque chose me manque).

Merci

Était-ce utile?

La solution

Vous pouvez également essayer le code suivant si vous souhaitez réellement transférer des structures sous forme de tableau d'octets:

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

Ceci convertit la valeur de l'objet donné en un tableau d'octets rawdata. J'ai pris cela dans le code que j'ai écrit précédemment et vous devrez peut-être l'adapter à vos besoins pour que cela fonctionne réellement. Je l'ai utilisé pour la communication avec du matériel doté de structures définies par l'utilisateur, mais cela devrait également fonctionner pour les types intégrés (après tout, ce sont des structures, n'est-ce pas?)

Pour aligner correctement les membres de la structure, utilisez l'attribut StructLayout pour spécifier un alignement sur un octet:

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

Ensuite, utilisez l'attribut MarshalAs selon vos besoins pour les champs, par exemple. pour les tableaux en ligne:

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

Le code permettant de récupérer la structure à partir du tableau d'octets ressemble à ceci:

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

Bien sûr, vous devez connaître le type de votre choix pour que cela fonctionne.

Notez que cela ne gérera pas l’endianisme pour lui-même. Dans mon projet, la plupart des champs n’étaient qu’un octet, alors peu importait, mais pour les quelques champs où c’était le cas, j’ai simplement rendu les champs privés et ajouté des propriétés publiques qui s’occuperaient de l’endianisme ( Le lien de Jon Skeet d'un commentaire à sa réponse peut vous aider, j'ai écrit quelques fonctions utilitaires pour cela car j'avais besoin seulement peu).

Lorsque j'en ai eu besoin, j'ai créé une classe Message qui stockerait la valeur brute (d'où la méthode GetValue, le code en haut est en fait le corps d'une méthode SetValue) et disposait d'une méthode pratique pour obtenir la valeur mise en forme. etc.

Autres conseils

Utilisez BitConverter.GetBytes ()

Vous devez d'abord convertir la valeur en son type natif, puis utiliser BitConverter pour obtenir les octets:

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

Voulez-vous dire la représentation définitive en mémoire? BitConverter.GetBytes (avec une surcharge choisie de manière appropriée par réflexion) vous renverra une représentation d'octet , mais pas nécessairement ce qu'il est actuellement en mémoire.

Peut-être que si vous donnez plus d'informations sur les raisons pour lesquelles vous le souhaitez, nous pourrons mieux vous aider.

EDIT: Je devrais ajouter que, dans tous les cas raisonnables auxquels je pourrais penser, BitConverter vous vous donnera la même représentation qu'en mémoire - mais il peut y avoir des situations étranges impliquant endianness et éventuellement des architectures étranges avec des représentations en virgule flottante pouvant donner des résultats étranges.

EDIT: Voici un exemple de programme complet démontrant comment vous pouvez vous y prendre:

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));
        }        
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top