F#区分用户定义类型的联合; 尊重自定义属性

bie*_*man 6 f# discriminated-union

我试图使用一个有区别的联合来表示一些用户定义的类型; 但是,构成DU案例的类型包含DU未遵守的自定义属性.例如,我正在编组一个文件头,其中包含头扩展中的一些可选字段,具体取决于编写该文件的程序.结构的字段还有一个自定义属性,允许结构的字段用正确的字节顺序封送,由下式给出[<endian>].给定一个通用的基本头结构,

[<Struct; StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)>]
type generic_header = {
    [<endian>] header_size: int16
    [<MarshalAs(UnmanagedType.ByValTStr, SizeConst = 55)>]
    file_version: string
    [<endian>] file_size: int16
    header_extension: bool
    }
Run Code Online (Sandbox Code Playgroud)

和带有+/-字段的标头扩展,具体取决于生成标头的程序,

[<Struct; StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)>]
    type header_extension = {
    [<endian>] extended_field_1: int16
    [<endian>] extended_field_2: float32
    [<MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)>]
    extended_array: byte[]
    [<endian>] extended_field_3: int16
    ...
    }
Run Code Online (Sandbox Code Playgroud)

是否有可能拥有一个可以容纳这些类型的区别联合(或甚至另一个结构),并且DU类型可用于将流编组到包含的结构中?如果我单独封送每种类型,那么endian属性会被尊重,我会获得正确的数据.

到目前为止我尝试过的是:

[<Struct>]
type file_header =
    | Header of Header: generic_header
    | Extension of Extension: header_extension
Run Code Online (Sandbox Code Playgroud)

要么:

[<Struct>] type file_header = | Header of generic_header * header_extension
Run Code Online (Sandbox Code Playgroud)

或者某些案例逻辑,根据generic_header的第一个字段的值执行以下操作之一:

[<Struct>] type file_header_from_prog_1 = | Header of generic_header * prog_1_header_extension
[<Struct>] type file_header_from_prog_2 = | Header of generic_header * prog_2_header_extension
[<Struct>] type file_header_from_prog_3 = | Header of generic_header * prog_3_header_extension
Run Code Online (Sandbox Code Playgroud)

但是,当我使用file_header类型进行封送处理时,它会正确地将正确数量的字节封送到结构中,但它不会考虑字段上的endian标记.

我的目标是构建一个"超类型",其中包含可以构成我正在编组的文件头的所有可能的扩展和类型,这样我就不必单独编组每种类型.有没有办法做到这一点?