2009-11-26 4 views
3

observer le exemple de code suivant:Comment déclarer une union en C#?

struct DDD 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 512, ArraySubType = UnmanagedType.I1)] 
    byte[] x; 
} 

struct BBB 
{ 
    DDD x; 
} 

struct CCC 
{ 
    DDD x; 
    ulong y; 
    ulong z; 
} 

[StructLayout(LayoutKind.Explicit)] 
struct AAA 
{ 
    [FieldOffsetAttribute(0)] 
    BBB a; 
    [FieldOffsetAttribute(0)] 
    CCC b; 
} 

Malheureusement, AAA ne peut pas être chargé, en essayant d'exécuter new AAA() échoue avec System.TypeLoadException: Could not load type 'AAA' from assembly 'Shunra.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=807fc02bc4ce69db' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.

Comment faire un accord avec elle?

Merci.

EDIT:

BTW, Ceci est une version dépouillée de Interop de MINIDUMP_CALLBACK_INPUT créé par PInvokeTool (struct d'origine est défini dans DbgHelp.h)

Répondre

-1

Je pense que vous devez ajouter un constructeur dans la structure pour instancier les types BBB et CCC, à leur tour, dans chacune des autres structures BBB et CCC, vous avez également besoin d'un constructeur pour instancier le type DDD.

 
struct DDD 
{ 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 512, ArraySubType = UnmanagedType.I1)] 
    byte[] x; 
} 

struct BBB 
{ 
    DDD x; 
    public BBB(){ 
    x = new DDD(); 
    } 
} 

struct CCC 
{ 
    DDD x; 
    ulong y; 
    ulong z; 
    public CCC(){ 
    x = new DDD(); 
    } 
} 

[StructLayout(LayoutKind.Explicit)] 
struct AAA 
{ 
    [FieldOffsetAttribute(0)] 
    BBB a; 
    [FieldOffsetAttribute(0)] 
    CCC b; 
    public AAA(){ 
    a = new BBB(); 
    b = new CCC(); 
    } 
} 

La seule Gotcha dans c'est l'instanciation de DDD struct qui est inconnu, comme vous l'avez déclaré x sur le terrain qui est un octet tableau [] et la taille est inconnue, de sorte que vous devez gérer celui-ci sur la base sur vos propres exigences. Peut-être passer dans le paramètre, peut-être un int indiquant la taille du tableau ...

Espérons que cela vous aide, Cordialement, Tom.

+0

Non, c'est tout simplement faux. Avez-vous lu le message d'erreur? – erikkallen

+0

@erikkallen: Merci pour les heads up ... sur une autre note ...La raison pour laquelle j'ai signalé ma publication était parce que je suis en train d'écrire un Dumper PE géré qui utilise struct et je suis tombé sur le gotcha car l'un des structs contenait un tableau d'octets dont la longueur est inconnue et avait de la difficulté à l'instancier par conséquent, je sentais que c'était à signaler au cas où quelqu'un aurait des difficultés..Mais merci quand même. :) – t0mm13b

2

Le problème est que, peu importe ce que vous spécifiez pour MarshalAsAttribute, un tableau est un objet géré. Pour que votre code fonctionne, vous devrez vous débarrasser du tableau géré. Pour ce faire, vous avez deux options:

Option 1:

Convertir le tableau à un tampon de taille fixe, ce qui signifie changer votre définition de DDD à ceci:

unsafe struct DDD { 
    [MarshalAsAttribute(UnmanagedType.ByValArray, SizeConst = 512, ArraySubType = UnmanagedType.I1)] 
    fixed byte x[512]; 
} 

(I » Je ne sais pas si le MarshalAsAttribute est nécessaire, mais j'en doute.)

Maintenant que vous utilisez une structure dangereuse, vous devez compiler avec le commutateur/unsafe.

Option 2:

Convertir le tableau à 512 octets de membres. Le moyen le plus simple serait d'utiliser 64 longs:

struct DDD { 
    long x1; 
    long x2; 
    long x3; 
    ... 
} 

Édition: Clarifié.

+0

Vous auriez besoin d'instancier x pour que cela fonctionne. – t0mm13b

+0

Merci, mais je souhaite éviter le code dangereux. Sinon, je pourrais juste écrire des pointeurs et copier les structures C textuellement. – mark

+0

Cela ne fonctionnera pas définitivement j'ai peur. – t0mm13b

Questions connexes