This can be demonstrated with a simple test class:
[MemoryPackable]
[GenerateTypeScript]
public partial class SimpleNullableTest
{
public float FloatValue { get; set; }
public float? NullableFloatValue { get; set; }
public double DoubleValue { get; set; }
public double? NullableDoubleValue { get; set; }
}
In TypeScript, when SimpleNullableTest.serialize() is called and the resultant bytes are deserialized in C# via MemoryPackSerializer.Deserialize<SimpleNullableTest>(), both NullableFloatValue and NullableDoubleValue are null regardless of their values on the TS side.
I've had a look at the bytes written by both the C# and TS sides. For nullable values, two values are written: HasValueFlag, Value. If HasValueFlag is 0, it's null, otherwise the value is Value. It looks like both HasValueFlag and Value must be the same width in bits, written little-endian.
On the C# side, for float and double, it appears to write and expect Int32 and Int64 respectively for HasValueFlag. However, the TS side writes float and double for HasValueFlag respectively. When those flags are interpreted by the C# side, their value, while non-zero, is not 1, thus the deserialized nullable value is always null.
This was observed in version 1.21.1 with a C# target framework of net8.0.
This can be demonstrated with a simple test class:
In TypeScript, when
SimpleNullableTest.serialize()
is called and the resultant bytes are deserialized in C# viaMemoryPackSerializer.Deserialize<SimpleNullableTest>()
, both NullableFloatValue and NullableDoubleValue are null regardless of their values on the TS side.I've had a look at the bytes written by both the C# and TS sides. For nullable values, two values are written: HasValueFlag, Value. If HasValueFlag is 0, it's null, otherwise the value is Value. It looks like both HasValueFlag and Value must be the same width in bits, written little-endian.
On the C# side, for float and double, it appears to write and expect Int32 and Int64 respectively for HasValueFlag. However, the TS side writes float and double for HasValueFlag respectively. When those flags are interpreted by the C# side, their value, while non-zero, is not 1, thus the deserialized nullable value is always null.
This was observed in version 1.21.1 with a C# target framework of net8.0.