jefffhaynes / BinarySerializer

A declarative serialization framework for controlling formatting of data at the byte and bit level using field bindings, converters, and code.
MIT License
290 stars 62 forks source link

Conditional serialization broken with trailing fields #184

Closed nullpainter closed 2 years ago

nullpainter commented 2 years ago

I am parsing a data structure where a fixed-length section may have a different shape depending on a discriminator property. I am using a combination of SerializeWhen and SerializeWhen with ComparisonOperator.NotEqual. This is working as expected unless there are fields after the conditional fields.

Fot the sample class:

 private record TestClass
 {
        [FieldOrder(0), FieldLength(5)]
        public string? Colour { get; set; }

        [FieldOrder(1), FieldLength(4)] 
        [SerializeWhen(nameof(Colour), "Brown")]
        [SerializeWhen(nameof(Colour), "Black")]
        public string? Animal { get; set; }

        [FieldOrder(2), FieldLength(4)]
        [SerializeWhen(nameof(Colour), "Brown", ComparisonOperator.NotEqual)]
        [SerializeWhen(nameof(Colour), "Black", ComparisonOperator.NotEqual)]
        public string? Fruit { get; set; }
  }

The inputs BrownBear and BlackBear correctly populates the Animal property with Bear. Likewise, the input GreenPear correctly populates the Fruit property with Pear.

However when the class is changed to add an additional property:

    private record TestClass
    {
        [FieldOrder(0), FieldLength(5)]
        public string? Colour { get; set; }

        [FieldOrder(1), FieldLength(4)] 
        [SerializeWhen(nameof(Colour), "Brown")]
        [SerializeWhen(nameof(Colour), "Black")]
        public string? Animal { get; set; }

        [FieldOrder(2), FieldLength(4)]
        [SerializeWhen(nameof(Colour), "Brown", ComparisonOperator.NotEqual)]
        [SerializeWhen(nameof(Colour), "Black", ComparisonOperator.NotEqual)]
        public string? Fruit { get; set; }

        [FieldOrder(3), FieldLength(7)]
        public string? Trailer { get; set; }
    }

The input BrownBearTrailer results in the Animal property being correctly set, but the Fruit property set to Trai and the Trailer property set to ler.

Am I misusing these properties, or is there something else I need to do to say that the two Animal and Fruit properties map to the same bytes?

nullpainter commented 2 years ago

Actually, this can be replicated without an additional property and just with additional input bytes. The first model above but with the input BrownBearTrailer results in the same behaviour.

nullpainter commented 2 years ago

I think I may have answered my own question - using a single field in my model and using Subtype instead of SerializeWhen did the trick.