Используя 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
Линия 6377 показывает следующее:
if requiresExtraField then
yield mkILInstanceField("__dummy",cenv.g.ilg.typ_int32,None,ILMemberAccess.Assembly) ]
Линия 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 предполагается, что структура не имеет полей экземпляра. Но написанный код проверяет, имеет ли структура какие-либо поля экземпляров, которые для большинства структур, включая мои, будут истинными. Я думаю, что последняя часть финального теста заключается в том, есть ли какие-либо параметры типового типа. Итак, requiresExtraField false для type A (не общий) и true для type B (общий тип).
Является ли это ошибкой компилятора, или код правильный? Если это правильно, то какова цель этого поля __dummy? Есть ли способ избежать этого?
В качестве другого теста я удалил одно и только поле экземпляра, и неудивительно, что я получил следующие размеры, показывая, что поле __dummy больше не добавлено:
// sizeof<AA> = 1
type AA = struct end
// sizeof<BB<int>> = 1
type BB<'T> = struct end
Причина, по которой я хочу иметь тип значения, а не ссылочный тип, заключается в том, что я буду хранить много этих объектов в своих структурах данных, а не просто передавать их.