Используя 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
Причина, по которой я хочу иметь тип значения, а не ссылочный тип, заключается в том, что я буду хранить много этих объектов в своих структурах данных, а не просто передавать их.