Ich habe in einem seltsamen Szenario Marshalling Gewerkschaften, die Arrays in C# /. NET enthalten. Betrachten Sie das folgende Programm:Marshal Union mit Arrays
namespace Marshal
{
class Program
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
struct InnerType
{
byte Foo;
//[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)]
//byte[] Bar;
}
[StructLayout(LayoutKind.Explicit, Pack = 1)]
struct UnionType
{
[FieldOffset(0)]
InnerType UnionMember1;
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)]
byte[] UnionMember2;
}
static void Main(string[] args)
{
Console.WriteLine(@"SizeOf UnionType: {0}", System.Runtime.InteropServices.Marshal.SizeOf(typeof(UnionType)));
}
}
}
Wenn Sie dieses Programm ausführen, erhalten Sie die folgende Ausnahme erhalten:
Could not load type 'UnionType' from assembly 'Marshal, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 0 that is incorrectly aligned or overlapped by a non-object field.
Nun, wenn Sie die beiden kommentierten aus Linien Kommentar-, läuft das Programm gut. Ich frage mich, warum das so ist. Warum beseitigt das Hinzufügen eines zusätzlichen Arrays zu InnerType das Problem? Übrigens spielt es keine Rolle, wie groß das Array ist. Ohne das Array sollten UnionMember1 und UnionMember2 in der Größe übereinstimmen. Mit dem Array stimmen ihre Größen nicht überein, dennoch werden keine Ausnahmen ausgelöst.
aktualisieren Ändern InnerType auf folgende Ursachen auch die Ausnahme (auf InnerType diesmal):
[StructLayout(LayoutKind.Explicit, Pack = 1)]
struct InnerType
{
[FieldOffset(0)]
byte Foo;
[FieldOffset(1)]
[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.Struct, SizeConst = 1)]
byte[] Bar;
}
Es scheint mir, dass dies auf den ursprünglichen Code äquivalent sein sollte (mit LayoutKind.Sequential
), wo byte[] Bar
ist unkommentiert.
Ich glaube nicht, dass das Problem hier etwas mit Wortgrenzen zu tun hat - ich benutze Pack = 1. Eher denke ich, es ist der zweite Teil der Ausnahme, "... es enthält ein Objektfeld bei offset 0, das ... durch ein Nicht-Objekt-Feld überlappt. " Byte [] ist ein Referenztyp, während das Byte selbst ein Werttyp ist. Ich kann sehen, dass "Byte Foo" am Ende "byte [] UnionMember2" überlappt. Dies erklärt jedoch immer noch nicht, warum das Auskommentieren von "byte [] bar" in meinem ursprünglichen Code die Ausnahme aufhebt.
Diese Beiträge sollten helfen: http://stackoverflow.com/questions/1190079/incorrectly-aligned-or-overlapped-by-a-non-object-field-error, http://stackoverflow.com/questions/ 4673099/union-in-c-sharp-falsch-ausgerichtet-oder-überlappt-mit-einem-Nicht-Objekt-Feld. Wenn Sie den Feld-Offset für das UnionMember2 auf 8 setzen, wird dies behoben. –
@David Venegoni - Danke! Ich habe diese aber schon angeschaut. # 1190079 ist spezifisch für den CF-Marshaller. Ich benutze keine CF und ich benutze Pack. # 4673099 hat eine Lösung für das Problem dieses Benutzers, erklärt aber nicht genau, was die Ausnahme verursacht. Wenn Sie einen Offset von 8 verwenden, wird die Ausnahme (und die Union) zwar gelöscht, es werden jedoch keine Hinweise darauf gegeben, warum das Hinzufügen von InnerType.bar die Ausnahme unterdrückt. – watkipet
Der Pinvoke-Marshaller lässt Sie keine Struktur zu einem Byte [] zuordnen, das ist keine sinnvolle Konvertierung. Eine Größe von 1 ist auch bizarr, das ist nur ein einfaches Byte. Sie dürfen auch keinen Referenztyp wie Byte [] mit einem Werttyp überlappen. Der Garbage Collector kann nicht mehr genau sehen, ob das Feld eine Referenz speichert. Um dies zu beheben, muss das Feld stattdessen als Puffer fester Größe deklariert werden. –