Skip to content

Commit

Permalink
Merge pull request MessagePack-CSharp#1314 from AArnott/fix1308
Browse files Browse the repository at this point in the history
Skip setting fields when the ctor already took the value
  • Loading branch information
AArnott authored Sep 2, 2021
2 parents 14556ae + 4e6b915 commit b676113
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -953,7 +953,7 @@ private static void BuildDeserializeInternalAssignFieldFromLocalVariableStringKe
{
foreach (var item in infoList)
{
if (item.MemberInfo == null || item.IsInitializedLocalVariable == null)
if (item.MemberInfo == null || item.IsInitializedLocalVariable == null || item.MemberInfo.IsWrittenByConstructor)
{
continue;
}
Expand Down Expand Up @@ -995,6 +995,11 @@ private static void BuildDeserializeInternalAssignFieldFromLocalVariableIntKey(O
continue;
}

if (item.MemberInfo.IsWrittenByConstructor)
{
continue;
}

// if (length <= key) { goto MEMBER_ASSIGNMENT_DONE; }
il.EmitLdloc(localLength);
il.EmitLdc_I4(key);
Expand Down Expand Up @@ -1786,7 +1791,7 @@ EmittableMember CreateEmittableMember(MemberInfo m)
{
FieldInfo = field,
IsReadable = allowPrivate || field.IsPublic,
IsWritable = (allowPrivate || field.IsPublic) && !field.IsInitOnly,
IsWritable = allowPrivate || (field.IsPublic && !field.IsInitOnly),
};
break;
default:
Expand Down Expand Up @@ -2066,7 +2071,14 @@ EmittableMember CreateEmittableMember(MemberInfo m)
}

var shouldUseFormatterResolver = false;
var membersArray = members.Where(m => m.IsExplicitContract || constructorParameters.Any(p => p.MemberInfo.Equals(m)) || m.IsWritable).ToArray();

// Mark each member that will be set by way of the constructor.
foreach (var item in constructorParameters)
{
item.MemberInfo.IsWrittenByConstructor = true;
}

var membersArray = members.Where(m => m.IsExplicitContract || m.IsWrittenByConstructor || m.IsWritable).ToArray();
foreach (var member in membersArray)
{
if (IsOptimizeTargetType(member.Type))
Expand Down Expand Up @@ -2219,6 +2231,8 @@ public bool IsField

public bool IsWritable { get; set; }

public bool IsWrittenByConstructor { get; set; }

/// <summary>
/// Gets a value indicating whether the property can only be set by an object initializer, a constructor, or another `init` member.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@
using System.Threading.Tasks;
using MessagePack.Resolvers;
using Xunit;
using Xunit.Abstractions;

namespace MessagePack.Tests
{
#if !ENABLE_IL2CPP

public class DataContractTest
{
private readonly ITestOutputHelper logger;

public DataContractTest(ITestOutputHelper logger)
{
this.logger = logger;
}

[DataContract]
public class MyClass
{
Expand Down Expand Up @@ -67,6 +74,23 @@ public class ClassWithPublicMembersWithoutAttributes
public int IgnoredField;
}

[DataContract]
public class ClassWithPrivateReadonlyDictionary
{
[DataMember(Name = "Key", Order = 0, EmitDefaultValue = false)]
private readonly Guid? key;

[DataMember(Name = "Body", Order = 1, EmitDefaultValue = false)]
private readonly Dictionary<string, object> body = new Dictionary<string, object>();

public ClassWithPrivateReadonlyDictionary(Guid? key)
{
this.key = key;
}

internal Dictionary<string, object> GetBody() => this.body;
}

[Fact]
public void SerializeOrder()
{
Expand Down Expand Up @@ -203,6 +227,32 @@ private static T DataContractSerializerRoundTrip<T>(T value)
ms.Position = 0;
return (T)dcs.ReadObject(ms);
}

[Fact]
public void DeserializeTypeWithPrivateReadonlyDictionary()
{
var before = new ClassWithPrivateReadonlyDictionary(Guid.NewGuid());
before.GetBody()["name"] = "my name";
byte[] bytes = MessagePackSerializer.Serialize(before, StandardResolverAllowPrivate.Options);
string json = MessagePackSerializer.ConvertToJson(bytes); // just for check that json has _body' values.
this.logger.WriteLine(json);

var after = MessagePackSerializer.Deserialize<ClassWithPrivateReadonlyDictionary>(bytes, StandardResolverAllowPrivate.Options);
Assert.Equal("my name", after.GetBody()["name"]);
}

[Fact]
public void DeserializeTypeWithPrivateReadonlyDictionary_DCS()
{
var before = new ClassWithPrivateReadonlyDictionary(Guid.NewGuid());
before.GetBody()["name"] = "my name";
DataContractSerializer dcs = new DataContractSerializer(typeof(ClassWithPrivateReadonlyDictionary));
var ms = new MemoryStream();
dcs.WriteObject(ms, before);
ms.Position = 0;
var after = (ClassWithPrivateReadonlyDictionary)dcs.ReadObject(ms);
Assert.Equal("my name", after.GetBody()["name"]);
}
}

#endif
Expand Down

0 comments on commit b676113

Please sign in to comment.