我遇到了一个涉及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
请注意GrayStruct
和ColorStruct
之间的相似性,Marshal.SizeOf
上的ColorStruct
扼流圈。由于Marshal.SizeOf
函数的存在,colorStructToUnit
似乎会抛出异常。如果删除该功能,则输出变为:
12
12
此外,如果我保留colorStructToUnit
功能,但替换:
val mutable Triple: Color[]
使用:
val mutable Triple: int[]
然后输出也变为:
12
12
感谢您对此问题的任何见解。
请注意,我在更大的代码库中遇到此问题,该代码库试图通过PInvoke与旧DLL进行交互。此问题似乎只影响结构中的枚举数组。一种解决方法是封装基础类型(即int[]
而不是Color[]
)然后将这些值转换为枚举,但该解决方案需要对几乎相同结构的多个定义。有没有更优雅的方法来克服这个问题?