将.NET泛型类型进行编组

13

这里有一个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#类型(尽管继承可以提供共同的头部)。

ArgumentException,带有他粘贴的消息。 - Reed Copsey
2
你遇到了具体的问题还是这只是一个学术性的问题? - Bryan
2个回答

11

通常情况下,泛型在任何交互操作场景中都不受支持。如果您尝试进行泛型类型或值的驱动程序调用(P/Invoke)或COM互操作,则会失败。因此,我预计Marshal.SizeOf在这种情况下未经测试或不受支持,因为它是一个特定于驱动程序调用的函数。


0

目前不知道聚合对象T的大小(如果T是引用类型,则为指针的大小,如果是值类型,则为大多数任意值的大小)。

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

但据我所知,在交互操作中不建议使用泛型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接