编组.NET泛型类型类型、NET

2023-09-03 01:29:01 作者:莫忘初心

下面是一个C#程序,试图 Marshal.SizeOf 在几个不同的类型:

 使用系统;
使用了System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)
类ACLASS {}

[StructLayout(LayoutKind.Sequential)
结构AStruct {}

[StructLayout(LayoutKind.Sequential)
B类{ACLASS值; }

[StructLayout(LayoutKind.Sequential)
类℃下T> 【T值; }

类节目
{
    静态无效M(对象o){Console.WriteLine(Marshal.SizeOf(O)); }

    静态无效的主要()
    {
        M(新ACLASS());
        M(新AStruct());
        M(新的B());
        M(新℃下AStruct>());
        M(新℃下ACLASS>());
    }
}
 

前四个调用M()成功,但在最后一个,一下SizeOf引发ArgumentException:

 类型C`1 [ACLASS]'不能被封送一个非托管的结构;任何有意义的大小或偏移,可以计算
 
8 .NET基础 类的基础

为什么呢?特别是,为什么在一下SizeOf呛℃下ACLASS> ,但不能在 B C< AStruct>

编辑:,因为它被询问的意见,这里的真实世界的问题,激发了我大部分是学术问题: 我打电话到一个C API,它基本上是C函数上操作(指针)许多不同类型的简单的C结构。都含有一个共同的报头后面是一个字段,但该字段的类型是不同的结构不同。在头一个标志表示该字段的类型。 (奇怪的,是的,但是这就是我有工作)。

如果我可以定义一个通用型 C< T> 和一个C#extern声明 M(C< T>),然后调用 M(C< INT>)在同一行,而 M(C<双>)在另一个,我想有一个简短而亲切的互操作解决方案。但考虑到JaredPar的回答,看来我必须做出一个单独的C#类型,每个结构(尽管继承可以提供通用报文头)。

解决方案

泛型作为一项规则,不支持任何互操作场景。双方的P / Invoke和COM互操作的,如果你试图封送泛型类型或值将会失败。因此,我希望 Marshal.SizeOf 是未经测试或不支持此方案,因为它是一个编组特定的功能。

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).

解决方案

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.