使用F#Interactive,您可以验证以下尺寸:
// sizeof<A> = 4 bytes
type A (i: int) = struct end
// sizeof<B<int>> = 8 bytes (use any type parameter)
type B<'T> (i: int) = struct end
额外大小的原因似乎是在通用情况下存在整数__dummy
字段。再次使用F#Interactive,您可以使用typeof
:
typeof<A>
显示DeclaredFields = [|Int32 i|]
typeof<B<int>>
显示DeclaredFields = [|Int32 i; Int32 __dummy|]
我不明白为什么添加了__dummy
字段。
我认为负责添加它的代码在这里:
https://github.com/fsharp/FSharp.Compiler.Service/blob/master/src/fsharp/ilxgen.fs
Line 6377显示了这一点:
if requiresExtraField then
yield mkILInstanceField("__dummy",cenv.g.ilg.typ_int32,None,ILMemberAccess.Assembly) ]
Line 6290是定义requiresExtraField
的地方:
let requiresExtraField =
let isEmptyStruct =
(match ilTypeDefKind with ILTypeDefKind.ValueType -> true | _ -> false) &&
// All structs are sequential by default
// Structs with no instance fields get size 1, pack 0
tycon.AllFieldsAsList |> List.exists (fun f -> not f.IsStatic)
isEmptyStruct && cenv.opts.workAroundReflectionEmitBugs && not tycon.TyparsNoRange.IsEmpty
我认为isEmptyStruct
应该意味着结构没有任何实例字段。但是编写的代码正在测试struct 是否具有任何实例字段,对于大多数结构体,包括我的结构字段都是真的。我认为最终测试的最后一部分是是否存在任何泛型类型参数。因此requiresExtraField
false
为type A
(非通用),true
为type B
(通用类型)。{/ p>
这是编译器错误,还是代码正确?如果它是正确的,那么这个__dummy
字段的目的是什么?有什么方法可以避免它吗?
作为另一项测试,我删除了我唯一的实例字段,毫不奇怪,我得到了以下尺寸,显示不再添加__dummy
字段:
// sizeof<AA> = 1
type AA = struct end
// sizeof<BB<int>> = 1
type BB<'T> = struct end
我想要一个值类型而不是引用类型的原因是我将在我的数据结构中存储大量这些对象,而不仅仅是传递它们。
答案 0 :(得分:1)
@jyoung在我原来的帖子下面的评论中给出了解释。
requiresExtraField
的最后一行也测试cenv.opts.workAroundReflectionEmitBugs
。此标记似乎在fscopts.fs中设置。代码行是:
workAroundReflectionEmitBugs=tcConfig.isInteractive; // REVIEW: is this still required?
因此,额外__dummy
字段的问题仅发生在F#Interactive。