Marshalling .NET generic types

.net, c#, generics, interop, marshalling

Solution

Generics as a rule are not supported in any interop scenario. Both P/Invoke and COM Interop will fail if you attempt to marshal a generic type or value. Hence I would expect Marshal.SizeOf to be untested or unsupported for this scenario as it is a marshal-specific function.

Problem

Here is a C# program that tries `Marshal.SizeOf` on a few different 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> { 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>()); } } ``` The first four calls to M() succeed, but on the last one, SizeOf throws an ArgumentException: ``` "Type 'C`1[AClass]' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed." ``` Why? Specifically, why does SizeOf choke on `C<AClass>`, but not on `B` or on `C<AStruct>`? EDIT: Because it was asked about in the comments, here's the "real-world" problem that inspired this mostly-academic question: I'm calling into a C API that is basically one C function that operates on (pointers to) lots of different types of simple C structures. All contain a common header followed by one field, but the type of that field is different in different structures. A flag in the header indicates the type of the field. (Strange, yes, but that's what I have to work with). If I could define a single generic type `C<T>` and a single C# extern declaration `M(C<T>)`, and then call `M(C<int>)` on one line, and `M(C<double>)` on another, I'd have a short and sweet interop solution. But given JaredPar's answer, it appears that I have to make a separate C# type for each structure (though inheritance can provide the common header).

Original source