F#P / Invoke Marshaling递归结构

时间:2011-01-11 02:58:59

标签: f# pinvoke recursive-datastructures

到目前为止,我看到的所有示例似乎都没有解决包含包含递归引用的结构联合的结构的问题。我试图为包含这些的结构编写一个封送程序,并且到目前为止已经失败了。

例如:

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#中表示这些结构的任何其他方法。

提前感谢您的时间。

1 个答案:

答案 0 :(得分:4)

你有两个问题。首先,任何相互递归的类型(无论是有区别的联合,类还是结构)都需要使用

来定义
type A = ... 
and B = ...

而不是

type A = ... 
type B = ...

(请注意,属性可以在单词type之前或之后,但只能在单词and ...之后。但是,如果你尝试这个,你会看到你只是得到一个不同的错误,因为结构不能直接递归为彼此的字段。如果struct A有一个结构B的字段,而结构B有一个结构A的字段(并且它们中的任何一个都有其他字段),那么大小将是无限的。请注意,您的C代码也是如此 - StructB包含MyStruct指针,而不是MyStruct本身。在.NET中,您可以使用IntPtr - 在F#中,您可以使用nativeint别名或nativeptr<MyStruct>。试试这个:

open System.Runtime.InteropServices

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 : nativeptr<MyStruct>

and [<Struct; StructLayout(LayoutKind.Explicit)>]MyStruct =
    [<FieldOffset(0)>] val discriminator : MyStructTag
    [<FieldOffset(4)>] val structA : StructA
    [<FieldOffset(4)>] val structB : StructB