Open abrasat opened 1 year ago
It should work. Is it not?
It works only if the Crc property is placed after the Subtype field. If I put it before (as I need in my application), it throws this exception:
Error serializing member 'Crc'. See inner exception for detail.
InvalidOperationException: Reverse binding not allowed on FieldValue attributes. Consider swapping source and target.
Yes, crc fields cannot appear before the data they are checking, as this is not strictly serialization.
Any other way to solve my problem? Maybe using a ValueConverter?
I tried to use the Crc32 built-in with my example using SerializeWhen and Subtypes (see #225 ). This is the code modification that I did:
public class ValueDataInfo
{
[FieldOrder(0)]
public ValueBlockType BlockType { get; set; } = ValueBlockType.PlainValue;
[FieldOrder(1)]
public UInt32 ParameterId { get; set; }
[FieldOrder(2)]
[FieldLength(8)]
public string Name { get; set; }
[FieldOrder(3)]
public UInt32 NrValues { get; set; }
[FieldOrder(4)]
public ValueDataType DataTypeId { get; set; } = ValueDataType.Datatype_Invalid;
[FieldOrder(5)]
[SerializeWhen(nameof(BlockType), ValueBlockType.PlainValue)]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Double, typeof(DoublePlainValuesDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Float, typeof(FloatPlainValuesDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Int16, typeof(Int16PlainValuesDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Int32, typeof(Int32PlainValuesDataBody))]
[SubtypeDefault(typeof(EmptyPlainValueDataBlock))]
[FieldCrc32(nameof(Crc))]
public PlainValueDataBlock Block { get; set; }
[FieldOrder(6)]
[SerializeWhen(nameof(BlockType), ValueBlockType.ValueWithDescriptor)]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Double, typeof(DoubleValuesWithDescriptorDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Float, typeof(FloatValuesWithDescriptorDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Int16, typeof(Int16ValuesWithDescriptorDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Int32, typeof(Int32ValuesWithDescriptorDataBody))]
[SubtypeDefault(typeof(EmptyDescriptorDataBlock))]
[FieldCrc32(nameof(Crc))]
public ValueWithDescriptorDataBlock DescriptorBlock { get; set; }
[FieldOrder(7)]
public ulong Crc { get; set; }
}
The following exception is thrown:
Error serializing member 'Crc'. See inner exception for detail. Inner exception: "Reverse binding not allowed on FieldValue attributes. Consider swapping source and target."
If I put the Crc32 attribute only on the first SerializeWhen option it seems to work, no excepion is generated:
...
[FieldOrder(5)]
[SerializeWhen(nameof(BlockType), ValueBlockType.PlainValue)]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Double, typeof(DoublePlainValuesDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Float, typeof(FloatPlainValuesDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Int16, typeof(Int16PlainValuesDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Int32, typeof(Int32PlainValuesDataBody))]
[SubtypeDefault(typeof(EmptyPlainValueDataBlock))]
[FieldCrc32(nameof(Crc))]
public PlainValueDataBlock Block { get; set; }
[FieldOrder(6)]
[SerializeWhen(nameof(BlockType), ValueBlockType.ValueWithDescriptor)]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Double, typeof(DoubleValuesWithDescriptorDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Float, typeof(FloatValuesWithDescriptorDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Int16, typeof(Int16ValuesWithDescriptorDataBody))]
[Subtype(nameof(DataTypeId), ValueDataType.Datatype_Int32, typeof(Int32ValuesWithDescriptorDataBody))]
[SubtypeDefault(typeof(EmptyDescriptorDataBlock))]
//[FieldCrc32(nameof(Crc))]
public ValueWithDescriptorDataBlock DescriptorBlock { get; set; }
[FieldOrder(7)]
public ulong Crc { get; set; }
...
@jefffhaynes could you please take a look, if related to #225 fix And also some questions: is there any method available to get the calculated Crc32 value after the serialization (for the cases it does not throw an exception)? Can the bound Crc property be marked with the [Ignore] attribute and still get calculated? And is it possible to get the byte-offset of a class property in the serialized byte-array?
I believe the issue is that the crc can only be used on a single field. If you need to calculate it over multiple fields, simply create a container class for those fields.
Is it possible to use the Crc32 built-in extension to calculate the checksum over a subtype field? For example in this class from PcapNgNet, how can a new field be added to calculate the Crc32 for the "BlockBody Body" field?