F#Marshal.SizeOf异常涉及结构

时间:2017-07-02 17:36:23

标签: struct enums f# marshalling sizeof

我遇到了一个涉及Marshal.SizeOf的运行时异常,我不明白。在删除了大量代码之后,我想出了一个演示该问题的小例子:

#nowarn "9"

open System.Runtime.InteropServices

type Gray = | Black = 0 | Gray = 1 | White = 2

[<Struct; StructLayout(LayoutKind.Sequential, Pack = 1)>]
type GrayStruct =
    [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)>]
    val mutable Triple: Gray[]

type Color = | Red = 0 | Green = 1 | Blue = 2

[<Struct; StructLayout(LayoutKind.Sequential, Pack = 1)>]
type ColorStruct =
    [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)>]
    val mutable Triple: Color[]

let colorStructToUnit (colorStruct: ColorStruct) = ()

printfn "%A" (Marshal.SizeOf(typeof<GrayStruct>))
printfn "%A" (Marshal.SizeOf(typeof<ColorStruct>))

使用fsi.exe(版本4.1)运行此示例会导致:

12
System.ArgumentException: Type 'FSI_0001+ColorStruct' cannot be marshaled as an unmanaged structure; no meaningful size or offset can be computed.
   at System.Runtime.InteropServices.Marshal.SizeOfHelper(Type t, Boolean throwIfNotMarshalable)
   at System.Runtime.InteropServices.Marshal.SizeOf(Type t)
   at <StartupCode$FSI_0001>.$FSI_0001.main@() in 
C:\f#\Example\example.fsx:line 21
Stopped due to error

请注意GrayStructColorStruct之间的相似性,Marshal.SizeOf上的ColorStruct扼流圈。由于Marshal.SizeOf函数的存在,colorStructToUnit似乎会抛出异常。如果删除该功能,则输出变为:

12
12

此外,如果我保留colorStructToUnit功能,但替换:

    val mutable Triple: Color[]

使用:

    val mutable Triple: int[]

然后输出也变为:

12
12

感谢您对此问题的任何见解。

请注意,我在更大的代码库中遇到此问题,该代码库试图通过PInvoke与旧DLL进行交互。此问题似乎只影响结构中的枚举数组。一种解决方法是封装基础类型(即int[]而不是Color[])然后将这些值转换为枚举,但该解决方案需要对几乎相同结构的多个定义。有没有更优雅的方法来克服这个问题?

0 个答案:

没有答案