Marshalling types génériques .NET

Voici un programme C # qui tente Marshal.SizeOf sur différents types:

 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 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()); M(new C()); } } 

Les quatre premiers appels à M () réussissent, mais sur le dernier, SizeOf lève une exception ArgumentException:

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

Pourquoi? Plus précisément, pourquoi SizeOf s’étouffe-t-il sur C , mais pas sur B ou sur C ?


EDIT: Comme il a été demandé dans les commentaires, voici le problème du “monde réel” qui a inspiré cette question essentiellement académique: j’appelle dans une API C qui est fondamentalement une fonction C qui opère sur de nombreux différents types de structures simples en C. Tous contiennent un en-tête commun suivi d’un champ, mais le type de ce champ est différent selon les structures. Un drapeau dans l’en-tête indique le type du champ. (Etrange, oui, mais c’est avec ça que je dois travailler).

Si je pouvais définir un seul type générique C et une seule déclaration externe C # M(C) , puis appeler M(C) sur une ligne et M(C) sur une autre , J’aurais une solution interop courte et douce. Mais étant donné la réponse de JaredPar, il apparaît que je dois créer un type C # distinct pour chaque structure (bien que l’inheritance puisse fournir l’en-tête commun).

En règle générale, les génériques ne sont pris en charge dans aucun scénario interop. P / Invoke et COM Interop échoueront tous les deux si vous tentez de définir un type ou une valeur générique. Par conséquent, je m’attendrais à ce que Marshal.SizeOf ne soit ni testé ni pris en charge pour ce scénario car il s’agit d’une fonction spécifique à marshal.

On ne sait pas quelle taille l’object agrégé T aurait (ce serait la taille d’un pointeur si T est un type de référence et surtout une valeur s’il s’agit d’un type de valeur).

Je pense que vous pouvez résoudre ce problème en définissant l’atsortingbut MarshalAs sur le champ ‘valeur’ ​​spécifiant le type le plus proche (par exemple, Unmanagedtype.SysInt). Notez que cela ne fonctionne toujours pas pour les types dits non mappables (c’est-à-dire les types pour lesquels les décalages et les tailles de champs ne peuvent pas être déduits facilement).

Mais autant que je sache, il n’est pas recommandé d’utiliser des génériques en interop.