这是一个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>
,而不会阻止B
或C<AStruct>
?
编辑:因为在评论中被问及,这是“真实世界”的问题,这启发了这个主要是学术性的问题: 我正在调用一个C API,它基本上是一个C函数,它操作(指向)许多不同类型的简单C结构。所有包含一个公共头,后跟一个字段,但该字段的类型在不同的结构中是不同的。标题中的标志表示字段的类型。 (奇怪,是的,但这就是我必须要合作的东西)。
如果我可以定义单个泛型类型C<T>
和单个C#extern声明M(C<T>)
,然后在一行上调用M(C<int>)
,在另一行调用M(C<double>)
,我有一个简短而甜蜜的互操作解决方案。但鉴于JaredPar的回答,似乎我必须为每个结构制作一个单独的C#类型(尽管继承可以提供公共头)。
答案 0 :(得分:8)
任何互操作方案都不支持泛型。如果您尝试封送泛型类型或值,则P / Invoke和COM Interop都将失败。因此,我希望Marshal.SizeOf可以在此方案中未经测试或不受支持,因为它是特定于编组的功能。
答案 1 :(得分:0)
不知道聚合对象T的大小(如果T是参考类型,则为指针的大小,如果是值类型,则大多为任何值)。
我认为您可以通过在字段'value'上设置MarshalAs属性来指定最匹配的类型(例如,Unmanagedtype.SysInt)来解决此问题。请注意,它仍然不适用于所谓的不可映射类型(即无法轻易推断出字段偏移和大小的类型)。
但是AFAIK,不建议在互操作中使用泛型。