编组.NET泛型类型

时间:2009-10-16 18:10:50

标签: c# .net generics interop marshalling

这是一个C#程序,它在几种不同的类型上尝试Marshal.SizeOf

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

对M()的前四次调用成功,但在最后一次调用时,SizeOf抛出ArgumentException:

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

为什么呢?具体来说,为什么SizeOf会阻塞C<AClass>,而不会阻止BC<AStruct>


编辑:因为在评论中被问及,这是“真实世界”的问题,这启发了这个主要是学术性的问题: 我正在调用一个C API,它基本上是一个C函数,它操作(指向)许多不同类型的简单C结构。所有包含一个公共头,后跟一个字段,但该字段的类型在不同的结构中是不同的。标题中的标志表示字段的类型。 (奇怪,是的,但这就是我必须要合作的东西)。

如果我可以定义单个泛型类型C<T>和单个C#extern声明M(C<T>),然后在一行上调用M(C<int>),在另一行调用M(C<double>),我有一个简短而甜蜜的互操作解决方案。但鉴于JaredPar的回答,似乎我必须为每个结构制作一个单独的C#类型(尽管继承可以提供公共头)。

2 个答案:

答案 0 :(得分:8)

任何互操作方案都不支持泛型。如果您尝试封送泛型类型或值,则P / Invoke和COM Interop都将失败。因此,我希望Marshal.SizeOf可以在此方案中未经测试或不受支持,因为它是特定于编组的功能。

答案 1 :(得分:0)

不知道聚合对象T的大小(如果T是参考类型,则为指针的大小,如果是值类型,则大多为任何值)。

我认为您可以通过在字段'value'上设置MarshalAs属性来指定最匹配的类型(例如,Unmanagedtype.SysInt)来解决此问题。请注意,它仍然不适用于所谓的不可映射类型(即无法轻易推断出字段偏移和大小的类型)。

但是AFAIK,不建议在互操作中使用泛型。