F# P/Invoke 编组递归结构
到目前为止,我见过的所有示例似乎都没有解决编组包含递归引用的结构联合的结构的问题。我正在尝试为包含这些的结构编写一个封送拆收器,但迄今为止失败了。
例如:
typedef enum {
My_StructA = 0x7878,
My_StructB
} MyStructTag;
typedef struct _MyStruct MyStruct;
struct _MyStruct {
MyStructTag discriminator;
union {
struct {
int a;
int b;
} StructA;
struct {
int c;
MyStruct* d;
} StructB;
} MyUnion;
};
我尝试按如下方式定义结构:
type MyStructTag =
| My_StructA = 0x7878
| My_StructB = 0x7879
[<Struct; StructLayout(LayoutKind.Sequential)>]
type StructA =
val mutable a : int
val mutable b : int
[<Struct; StructLayout(LayoutKind.Sequential)>]
type StructB =
val mutable c : int
val mutable d : MyStruct
[<Struct; StructLayout(LayoutKind.Explicit)>]
type MyStruct =
[<FieldOffset(0)>] val discriminator : MyStructTag
[<FieldOffset(4)>] val structA : StructA
[<FieldOffset(4)>] val structB : StructB
请注意,我费心显式定义 MyStruct 的原因是为了让自己在为此结构编写自定义封送拆收器时能够使用 Marshal.OffsetOf() 和 Marshal.SizeOf()。据我所知,编写自定义封送拆收器是处理联合的唯一方法。如果我错了,参考资料将不胜感激!
编写上述代码时收到的错误是:
error FS0039: The type 'MyStruct' is not defined
我认为这是因为只能递归定义可区分的联合类型。但是,我不知道有任何其他方法可以在 F# 中表示这些结构。
预先感谢您抽出时间。
None of the examples I have seen thus far appear to address the problem of marshaling a structure containing a union of structures that contain recursive references. I am attempting to write a marshaler for a structure which contains these and have so far failed.
For example:
typedef enum {
My_StructA = 0x7878,
My_StructB
} MyStructTag;
typedef struct _MyStruct MyStruct;
struct _MyStruct {
MyStructTag discriminator;
union {
struct {
int a;
int b;
} StructA;
struct {
int c;
MyStruct* d;
} StructB;
} MyUnion;
};
I attempted to define the structures as follows:
type MyStructTag =
| My_StructA = 0x7878
| My_StructB = 0x7879
[<Struct; StructLayout(LayoutKind.Sequential)>]
type StructA =
val mutable a : int
val mutable b : int
[<Struct; StructLayout(LayoutKind.Sequential)>]
type StructB =
val mutable c : int
val mutable d : MyStruct
[<Struct; StructLayout(LayoutKind.Explicit)>]
type MyStruct =
[<FieldOffset(0)>] val discriminator : MyStructTag
[<FieldOffset(4)>] val structA : StructA
[<FieldOffset(4)>] val structB : StructB
Note that the reason I bothered to define MyStruct explicitly is to allow myself to make use of Marshal.OffsetOf() and Marshal.SizeOf() when writing the custom marshaler for this structure. From what I have seen, writing a custom marshaler is the only way to handle unions. If I am wrong about that, references would be greatly appreciated!
The error I receive when writing the above code is:
error FS0039: The type 'MyStruct' is not defined
I assume this is because only discriminated union types can be defined recursively. However, I am not aware of any other way to represent these structures in F#.
Thank you in advance for your time.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你有两个问题。首先,任何相互递归类型(无论是可区分的联合、类还是结构)都需要使用
而不是
定义(并注意属性可以出现在单词
type
之前或之后,但只能在词和
...)。但是,如果您尝试这样做,您会发现您只是收到了不同的错误,因为结构不能作为彼此的字段直接递归。如果结构体 A 有一个结构体 B 的字段,并且结构体 B 有一个结构体 A 的字段(并且它们中的任何一个都有任何其他字段),那么大小将是无限的。请注意,您的 C 代码也是如此 -StructB
包含指向MyStruct
的指针,而不是MyStruct
> 本身。在 .NET 中,您可以使用IntPtr
来实现此目的 - 在 F# 中,您可以使用nativeint
别名或nativeptr
。试试这个:You've got two problems. First of all, any mutually recursive types (whether discriminated unions, classes, or structs) need to be defined using
rather than
(and note that attributes can come before or after the word
type
, but only after the wordand
...). However, if you try this, you'll see that you just get a different error, because structs can't be directly recursive as fields of each other. If struct A had a field which was a struct B and struct B had a field which was a struct A (and either of them had any other fields), then the size would be infinite. Note that this is true of your C code as well -StructB
contains a pointer to aMyStruct
, not aMyStruct
itself. In .NET, you can use anIntPtr
for this - in F# you can use thenativeint
alias ornativeptr<MyStruct>
. Try this: