2009-10-16 24 views
7

Hier ist ein C# Programm, das Marshal.SizeOf auf ein paar verschiedenen Arten versucht:Rangierung .NET generische Typen

using System; 
using System.Runtime.InteropServices; 

[StructLayout(LayoutKind.Sequential)] 
class AClass { } 

[StructLayout(LayoutKind.Sequential)] 
struct AStruct { } 

[StructLayout(LayoutKind.Sequential)] 
class B { AClass value; } 

[StructLayout(LayoutKind.Sequential)] 
class C<T> { T value; } 

class Program 
{ 
    static void M(object o) { Console.WriteLine(Marshal.SizeOf(o)); } 

    static void Main() 
    { 
     M(new AClass()); 
     M(new AStruct()); 
     M(new B()); 
     M(new C<AStruct>()); 
     M(new C<AClass>()); 
    } 
} 

Die ersten vier Anrufe M() erfolgreich zu sein, aber auf dem letzten, wirft SizeOf ein Argument:

"Type 'C`1[AClass]' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed." 

Warum? Insbesondere, warum SizeOf auf C<AClass>, aber nicht auf B oder auf C<AStruct> Drossel?


EDIT: Weil es in den Kommentaren gefragt wurde, hier ist das „real-world“ Problem, dass diese meist akademische Frage inspiriert: ich in einen C-API bin aufrufe, die im Grunde eine C Funktion, die auf viele verschiedene Arten einfacher C-Strukturen (Zeiger auf) einwirkt. Alle enthalten einen gemeinsamen Header gefolgt von einem Feld, aber der Typ dieses Feldes unterscheidet sich in verschiedenen Strukturen. Ein Flag in der Kopfzeile zeigt den Typ des Feldes an. (Seltsam, ja, aber damit muss ich arbeiten).

Wenn ich einen einzelnen generischen Typen C<T> und eine einzelnen C# extern-Deklaration M(C<T>) definieren könnte und dann M(C<int>) auf einer Linie nennen, und M(C<double>) auf einem anderen, würde ich eine kurze und süße Interop Lösung. Aber angesichts JaredPars Antwort scheint es, dass ich für jede Struktur einen eigenen C# -Typ machen muss (obwohl die Vererbung den gemeinsamen Header liefern kann).

+0

Welche Ausnahme wird ausgelöst? –

+0

ArgumentException mit der Nachricht, die er eingefügt hat. –

+0

@Philipp: gerade bearbeitet, um das zu klären, danke. – Gabriel

Antwort

7

Generics werden in der Regel in keinem Interop-Szenario unterstützt. Sowohl P/Invoke als auch COM Interop schlagen fehl, wenn Sie versuchen, einen generischen Typ oder Wert zu marshalieren. Daher würde ich erwarten, dass Marshal.SizeOf für dieses Szenario nicht getestet oder nicht unterstützt wird, da es eine Marshal-spezifische Funktion ist.

0

Es ist nicht bekannt, wie groß das aggregierte Objekt T wäre (es wäre die Größe eines Zeigers, wenn T ein Referenztyp und meistens ein beliebiger Wert ist, wenn es ein Werttyp ist).

Ich denke, Sie können dieses Problem lösen, indem Sie das Attribut MarshalAs für das Feld 'value' festlegen, das den am besten passenden Typ angibt (z. B. Unmanagedtype.SysInt). Beachten Sie, dass es immer noch nicht für so genannte nicht-mappable Typen (d. H. Typen, für die Felder Offsets und Größen nicht einfach abgeleitet werden können) funktioniert.

Aber AFAIK, es wird nicht empfohlen, Generika in Interop zu verwenden.