C# StructLayout.Explicite Question
J'essaie de comprendre pourquoi le deuxième exemple ci-dessous fonctionne sans problèmes, mais le premier exemple me donne l'exception ci-dessous. Il me semble que les deux exemples devraient vous donner une exception fondée sur la description. Quelqu'un peut-il m'éclairer?
Exception Non Gérée:
Système.TypeLoadException: ne Peut pas
type de charge 'StructTest.OuterType " de
l'assembly 'StructTest, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null'
parce qu'il contient un champ d'objet à
l'offset 0 qui est mal aligné
ou chevauché par un non-objet champ.
au StructTest.Programme.Main(String[]
args) Appuyez sur n'importe quelle touche pour continuer . . .
Exemple 1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StructTest
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct InnerType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
char[] buffer;
}
[StructLayout(LayoutKind.Explicit)]
struct OuterType
{
[FieldOffset(0)]
int someValue;
[FieldOffset(0)]
InnerType someOtherValue;
}
class Program
{
static void Main(string[] args)
{
OuterType t = new OuterType();
System.Console.WriteLine(t);
}
}
}
Exemple 2
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
namespace StructTest
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct InnerType
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 100)]
char[] buffer;
}
[StructLayout(LayoutKind.Explicit)]
struct OuterType
{
[FieldOffset(4)]
private int someValue;
[FieldOffset(0)]
InnerType someOtherValue;
}
class Program
{
static void Main(string[] args)
{
OuterType t = new OuterType();
System.Console.WriteLine(t);
}
}
}
OriginalL'auteur Taylor Leese | 2009-07-25
Vous devez vous connecter pour publier un commentaire.
Le common language runtime contient un vérificateur qui fait que l'exécution de code (vérifiable IL) ne peut pas corrompre la mémoire dans la gestion de l'environnement. Cela vous évite de déclarer une telle structure dans les champs qui se chevauchent. Fondamentalement, votre structure contient deux données membres. Un entier (4 octets) et un natif entier (la taille du pointeur). Sur un 32 bits, CLR, dans lequel vous êtes probablement en cours d'exécution de votre code, le
char[]
prendra 4 octets, donc si vous mettez l'entier inférieur à quatre octets du début de la structure, vous aurez le chevauchement des champs. Il est intéressant de noter que deux de vos extraits de code avec d'échouer sur une version 64 bits de l'exécution, comme le pointeur de la taille est de 8 octets.Oui. Il va travailler sur x64 CLR avec des décalages 8 et le 0. Notez que tandis que l'extrait de code fonctionne, si vous le faites dans un monde réel de l'application, vous êtes probablement l'interfaçage avec certains non géré trucs, qui attend de l'exacte des décalages. Si vous le réglez à 8, il peut échouer sur 32 bits machines (pas de cet extrait de lui-même, mais le code non managé vous êtes l'interfaçage avec).
Par ailleurs, vous ont chevauchement des champs si ils sont de non géré types, mais un .NET tableau est un type de référence (qui ne peut pas être considéré comme un non géré par C# spec). Si vous ne pouvez pas avoir un type de référence en tant que membre d'un syndicat en C#. Si vous avez vraiment besoin de cela, vous devriez envisager d'utiliser des choses comme les types de pointeur que les membres de la structure au lieu d'un tableau.
Merci. Je suis à la recherche en utilisant un dangereux struct fixes avec un char de taille 100 en OuterType directement plutôt que d'utiliser un InnerType. Il semble que cela peut être une meilleure approche.
Les règles sont encore plus obscures. Deux champs de types de référence (même complètement indépendants) se chevauchent, auquel cas l'assemblée est valide, mais non vérifiable (donc ça va fonctionner dans FullTrust). Donc, vous pouvez toujours gâcher les choses assez mauvais par le chevauchement des références à des types incompatibles. Je pense que la raison pour laquelle "chevauchement partiel" restriction est qu'il est absolument garanti à coup GC hors de l'eau. Alors qu'avec la référence complète de chevauchement GC fera très bien, et il peut effectivement être utile (pour enregistrer le casting d'exécution typechecks) lorsque vous avez un discriminateur de champ pour garder une trace du type.
OriginalL'auteur Mehrdad Afshari
J'ai pensé répondre avec la solution que j'ai utilisée pour créer l'union, qui a été mon intention de départ. J'ai utilisé un dangereux struct et un tableau fixe, puis utilisé une propriété d'interagir avec le tableau fixe. Je crois que cela devrait faire ce que je veux.
OriginalL'auteur Taylor Leese