Bug description
Readonly fields overwritten after constructor when using allow private.
Repro steps
[MessagePackObject]
public class Test
{
[Key(0)]
readonly string _test;
[SerializationConstructor]
public Test(string test)
{
_test = test ?? "I am never null :D";
}
[IgnoreMember]
public string Prop => _test;
}
[Fact]
public void AllowPrivateTest()
{
// write an empty array to seq
using var seq = new Sequence<byte>();
var writer = new MessagePackWriter(seq);
writer.WriteArrayHeader(0);
writer.Flush();
// deserialize as Test
var data = seq.AsReadOnlySequence;
var resolver = StandardResolverAllowPrivate.Instance;
var options = MessagePackSerializerOptions.Standard.WithResolver(StandardResolverAllowPrivate.Instance);
var test = MessagePackSerializer.Deserialize<Test>(in data, options);
// check test
Assert.NotNull(test.Prop);
}
The generated code here produces a call to the constructor (which assigns _test), then an assignment to the field _test.
Expected behavior
Only the constructor should be called, the field should not be overwritten after.
Actual behavior
The field is overwritten after the constructor has returned.
- Version used: v2.2.85
- Runtime: (e.g. .NET Framework, .NET Core, Unity, mono, etc.) .NET Core 3.1
Additional context
I believe the issue stems from the following:
member = new EmittableMember
{
FieldInfo = field,
IsReadable = allowPrivate || field.IsPublic,
IsWritable = allowPrivate || (field.IsPublic && !field.IsInitOnly),
StringKey = firstMemberByName ? item.Name : $"{item.DeclaringType.FullName}.{item.Name}",
};
In here the test for IsWritable will always be true if allowPrivate is true. Rather, it should probably be (allowPrivate || field.IsPublic) && !field.IsInitOnly.
Bug description
Readonly fields overwritten after constructor when using allow private.
Repro steps
The generated code here produces a call to the constructor (which assigns
_test), then an assignment to the field_test.Expected behavior
Only the constructor should be called, the field should not be overwritten after.
Actual behavior
The field is overwritten after the constructor has returned.
Additional context
I believe the issue stems from the following:
In here the test for
IsWritablewill always betrueifallowPrivateis true. Rather, it should probably be(allowPrivate || field.IsPublic) && !field.IsInitOnly.