Merge pull request #1093 from AArnott/develop

Merge master into develop
This commit is contained in:
Andrew Arnott 2020-10-25 11:39:54 -06:00 коммит произвёл GitHub
Родитель f86ec028be 12373f814f
Коммит 5a6cda6f9f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
6 изменённых файлов: 530 добавлений и 5 удалений

Просмотреть файл

@ -2429,6 +2429,112 @@ namespace MessagePack.Formatters.SharedData
}
}
public sealed class GenericConstrainedClassIntKeyFormatter<T1, T2> : global::MessagePack.Formatters.IMessagePackFormatter<global::SharedData.GenericConstrainedClassIntKey<T1, T2>>
where T1 : class
where T2 : class, global::System.Collections.Generic.IEqualityComparer<T1>
{
public void Serialize(ref global::MessagePack.MessagePackWriter writer, global::SharedData.GenericConstrainedClassIntKey<T1, T2> value, global::MessagePack.MessagePackSerializerOptions options)
{
if (value == null)
{
writer.WriteNil();
return;
}
global::MessagePack.IFormatterResolver formatterResolver = options.Resolver;
writer.WriteArrayHeader(2);
formatterResolver.GetFormatterWithVerify<T1>().Serialize(ref writer, value.MyProperty0, options);
formatterResolver.GetFormatterWithVerify<T2>().Serialize(ref writer, value.Comparer, options);
}
public global::SharedData.GenericConstrainedClassIntKey<T1, T2> Deserialize(ref global::MessagePack.MessagePackReader reader, global::MessagePack.MessagePackSerializerOptions options)
{
if (reader.TryReadNil())
{
return null;
}
options.Security.DepthStep(ref reader);
global::MessagePack.IFormatterResolver formatterResolver = options.Resolver;
var length = reader.ReadArrayHeader();
var __MyProperty0__ = default(T1);
var __Comparer__ = default(T2);
for (int i = 0; i < length; i++)
{
switch (i)
{
case 0:
__MyProperty0__ = formatterResolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options);
break;
case 1:
__Comparer__ = formatterResolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options);
break;
default:
reader.Skip();
break;
}
}
var ____result = new global::SharedData.GenericConstrainedClassIntKey<T1, T2>();
____result.MyProperty0 = __MyProperty0__;
____result.Comparer = __Comparer__;
reader.Depth--;
return ____result;
}
}
public sealed class GenericConstrainedStructIntKeyFormatter<T1, T2> : global::MessagePack.Formatters.IMessagePackFormatter<global::SharedData.GenericConstrainedStructIntKey<T1, T2>>
where T1 : unmanaged
where T2 : unmanaged, global::System.Collections.Generic.IEqualityComparer<T1>
{
public void Serialize(ref global::MessagePack.MessagePackWriter writer, global::SharedData.GenericConstrainedStructIntKey<T1, T2> value, global::MessagePack.MessagePackSerializerOptions options)
{
global::MessagePack.IFormatterResolver formatterResolver = options.Resolver;
writer.WriteArrayHeader(2);
formatterResolver.GetFormatterWithVerify<T1>().Serialize(ref writer, value.MyProperty0, options);
formatterResolver.GetFormatterWithVerify<T2>().Serialize(ref writer, value.Comparer, options);
}
public global::SharedData.GenericConstrainedStructIntKey<T1, T2> Deserialize(ref global::MessagePack.MessagePackReader reader, global::MessagePack.MessagePackSerializerOptions options)
{
if (reader.TryReadNil())
{
throw new global::System.InvalidOperationException("typecode is null, struct not supported");
}
options.Security.DepthStep(ref reader);
global::MessagePack.IFormatterResolver formatterResolver = options.Resolver;
var length = reader.ReadArrayHeader();
var __MyProperty0__ = default(T1);
var __Comparer__ = default(T2);
for (int i = 0; i < length; i++)
{
switch (i)
{
case 0:
__MyProperty0__ = formatterResolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options);
break;
case 1:
__Comparer__ = formatterResolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options);
break;
default:
reader.Skip();
break;
}
}
var ____result = new global::SharedData.GenericConstrainedStructIntKey<T1, T2>();
____result.MyProperty0 = __MyProperty0__;
____result.Comparer = __Comparer__;
reader.Depth--;
return ____result;
}
}
public sealed class GenericStructFormatter<T1, T2> : global::MessagePack.Formatters.IMessagePackFormatter<global::SharedData.GenericStruct<T1, T2>>
{
@ -3927,6 +4033,144 @@ namespace MessagePack.Formatters.SharedData
}
}
public sealed class GenericConstrainedClassStringKeyFormatter<T1, T2> : global::MessagePack.Formatters.IMessagePackFormatter<global::SharedData.GenericConstrainedClassStringKey<T1, T2>>
where T1 : class
where T2 : class, global::System.Collections.Generic.IEqualityComparer<T1>
{
// MyProperty0
private static global::System.ReadOnlySpan<byte> GetSpan_MyProperty0() => new byte[1 + 11] { 171, 77, 121, 80, 114, 111, 112, 101, 114, 116, 121, 48 };
// Comparer
private static global::System.ReadOnlySpan<byte> GetSpan_Comparer() => new byte[1 + 8] { 168, 67, 111, 109, 112, 97, 114, 101, 114 };
public void Serialize(ref global::MessagePack.MessagePackWriter writer, global::SharedData.GenericConstrainedClassStringKey<T1, T2> value, global::MessagePack.MessagePackSerializerOptions options)
{
if (value is null)
{
writer.WriteNil();
return;
}
IFormatterResolver formatterResolver = options.Resolver;
writer.WriteMapHeader(2);
writer.WriteRaw(GetSpan_MyProperty0());
formatterResolver.GetFormatterWithVerify<T1>().Serialize(ref writer, value.MyProperty0, options);
writer.WriteRaw(GetSpan_Comparer());
formatterResolver.GetFormatterWithVerify<T2>().Serialize(ref writer, value.Comparer, options);
}
public global::SharedData.GenericConstrainedClassStringKey<T1, T2> Deserialize(ref global::MessagePack.MessagePackReader reader, global::MessagePack.MessagePackSerializerOptions options)
{
if (reader.TryReadNil())
{
return null;
}
options.Security.DepthStep(ref reader);
IFormatterResolver formatterResolver = options.Resolver;
var length = reader.ReadMapHeader();
var __MyProperty0__ = default(T1);
var __Comparer__ = default(T2);
for (int i = 0; i < length; i++)
{
ReadOnlySpan<byte> stringKey = global::MessagePack.Internal.CodeGenHelpers.ReadStringSpan(ref reader);
switch (stringKey.Length)
{
default:
FAIL:
reader.Skip();
continue;
case 11:
if (!global::System.MemoryExtensions.SequenceEqual(stringKey, GetSpan_MyProperty0().Slice(1))) { goto FAIL; }
__MyProperty0__ = formatterResolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options);
continue;
case 8:
if (global::MessagePack.Internal.AutomataKeyGen.GetKey(ref stringKey) != 8243120455795175235UL) { goto FAIL; }
__Comparer__ = formatterResolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options);
continue;
}
}
var ____result = new global::SharedData.GenericConstrainedClassStringKey<T1, T2>()
{
MyProperty0 = __MyProperty0__,
Comparer = __Comparer__,
};
reader.Depth--;
return ____result;
}
}
public sealed class GenericConstrainedStructStringKeyFormatter<T1, T2> : global::MessagePack.Formatters.IMessagePackFormatter<global::SharedData.GenericConstrainedStructStringKey<T1, T2>>
where T1 : unmanaged
where T2 : unmanaged, global::System.Collections.Generic.IEqualityComparer<T1>
{
// MyProperty0
private static global::System.ReadOnlySpan<byte> GetSpan_MyProperty0() => new byte[1 + 11] { 171, 77, 121, 80, 114, 111, 112, 101, 114, 116, 121, 48 };
// Comparer
private static global::System.ReadOnlySpan<byte> GetSpan_Comparer() => new byte[1 + 8] { 168, 67, 111, 109, 112, 97, 114, 101, 114 };
public void Serialize(ref global::MessagePack.MessagePackWriter writer, global::SharedData.GenericConstrainedStructStringKey<T1, T2> value, global::MessagePack.MessagePackSerializerOptions options)
{
IFormatterResolver formatterResolver = options.Resolver;
writer.WriteMapHeader(2);
writer.WriteRaw(GetSpan_MyProperty0());
formatterResolver.GetFormatterWithVerify<T1>().Serialize(ref writer, value.MyProperty0, options);
writer.WriteRaw(GetSpan_Comparer());
formatterResolver.GetFormatterWithVerify<T2>().Serialize(ref writer, value.Comparer, options);
}
public global::SharedData.GenericConstrainedStructStringKey<T1, T2> Deserialize(ref global::MessagePack.MessagePackReader reader, global::MessagePack.MessagePackSerializerOptions options)
{
if (reader.TryReadNil())
{
throw new global::System.InvalidOperationException("typecode is null, struct not supported");
}
options.Security.DepthStep(ref reader);
IFormatterResolver formatterResolver = options.Resolver;
var length = reader.ReadMapHeader();
var __MyProperty0__ = default(T1);
var __Comparer__ = default(T2);
for (int i = 0; i < length; i++)
{
ReadOnlySpan<byte> stringKey = global::MessagePack.Internal.CodeGenHelpers.ReadStringSpan(ref reader);
switch (stringKey.Length)
{
default:
FAIL:
reader.Skip();
continue;
case 11:
if (!global::System.MemoryExtensions.SequenceEqual(stringKey, GetSpan_MyProperty0().Slice(1))) { goto FAIL; }
__MyProperty0__ = formatterResolver.GetFormatterWithVerify<T1>().Deserialize(ref reader, options);
continue;
case 8:
if (global::MessagePack.Internal.AutomataKeyGen.GetKey(ref stringKey) != 8243120455795175235UL) { goto FAIL; }
__Comparer__ = formatterResolver.GetFormatterWithVerify<T2>().Deserialize(ref reader, options);
continue;
}
}
var ____result = new global::SharedData.GenericConstrainedStructStringKey<T1, T2>()
{
MyProperty0 = __MyProperty0__,
Comparer = __Comparer__,
};
reader.Depth--;
return ____result;
}
}
public sealed class NonEmpty2Formatter : global::MessagePack.Formatters.IMessagePackFormatter<global::SharedData.NonEmpty2>
{
// MyProperty

Просмотреть файл

@ -56,14 +56,22 @@ foreach (var objInfo in ObjectSerializationInfos)
list.Add(new ValueTuple<MemberSerializationInfo, byte[]>(member, binary));
}
string formatterName = objInfo.Name + (objInfo.IsOpenGenericType ? $"Formatter<{string.Join(",", (object[])objInfo.GenericTypeParameters)}>" : "Formatter");
string formatterName = objInfo.Name + (objInfo.IsOpenGenericType ? $"Formatter<{string.Join(", ", objInfo.GenericTypeParameters.Select(x => x.Name))}>" : "Formatter");
bool isFormatterResolverNecessary = ShouldUseFormatterResolverHelper.ShouldUseFormatterResolver(objInfo.Members);
this.Write("\r\n public sealed class ");
this.Write(this.ToStringHelper.ToStringWithCulture(formatterName));
this.Write(" : global::MessagePack.Formatters.IMessagePackFormatter<");
this.Write(this.ToStringHelper.ToStringWithCulture(objInfo.FullName));
this.Write(">\r\n {\r\n");
this.Write(">\r\n");
foreach (var typeArg in objInfo.GenericTypeParameters.Where(x => x.HasConstraints)) {
this.Write(" where ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeArg.Name));
this.Write(" : ");
this.Write(this.ToStringHelper.ToStringWithCulture(typeArg.Constraints));
this.Write("\r\n");
}
this.Write(" {\r\n");
foreach (var memberAndBinary in list)
{

Просмотреть файл

@ -37,11 +37,14 @@ foreach (var objInfo in ObjectSerializationInfos)
list.Add(new ValueTuple<MemberSerializationInfo, byte[]>(member, binary));
}
string formatterName = objInfo.Name + (objInfo.IsOpenGenericType ? $"Formatter<{string.Join(",", (object[])objInfo.GenericTypeParameters)}>" : "Formatter");
string formatterName = objInfo.Name + (objInfo.IsOpenGenericType ? $"Formatter<{string.Join(", ", objInfo.GenericTypeParameters.Select(x => x.Name))}>" : "Formatter");
bool isFormatterResolverNecessary = ShouldUseFormatterResolverHelper.ShouldUseFormatterResolver(objInfo.Members);
#>
public sealed class <#= formatterName #> : global::MessagePack.Formatters.IMessagePackFormatter<<#= objInfo.FullName #>>
<# foreach (var typeArg in objInfo.GenericTypeParameters.Where(x => x.HasConstraints)) {#>
where <#= typeArg.Name #> : <#= typeArg.Constraints #>
<# }#>
{
<#
foreach (var memberAndBinary in list)

Просмотреть файл

@ -1617,8 +1617,14 @@ namespace MessagePack.Internal
if (isIntKey)
{
member.IntKey = key.IntKey.Value;
if (intMembers.ContainsKey(member.IntKey))
if (intMembers.TryGetValue(member.IntKey, out EmittableMember conflictingMember))
{
// Quietly skip duplicate if this is an override property.
if ((conflictingMember.PropertyInfo.SetMethod?.IsVirtual ?? false) || (conflictingMember.PropertyInfo.GetMethod?.IsVirtual ?? false))
{
continue;
}
throw new MessagePackDynamicObjectResolverException("key is duplicated, all members key must be unique." + " type: " + type.FullName + " member:" + item.Name);
}
@ -1627,8 +1633,14 @@ namespace MessagePack.Internal
else
{
member.StringKey = key.StringKey;
if (stringMembers.ContainsKey(member.StringKey))
if (stringMembers.TryGetValue(member.StringKey, out EmittableMember conflictingMember))
{
// Quietly skip duplicate if this is an override property.
if ((conflictingMember.PropertyInfo.SetMethod?.IsVirtual ?? false) || (conflictingMember.PropertyInfo.GetMethod?.IsVirtual ?? false))
{
continue;
}
throw new MessagePackDynamicObjectResolverException("key is duplicated, all members key must be unique." + " type: " + type.FullName + " member:" + item.Name);
}

Просмотреть файл

@ -467,6 +467,50 @@ namespace SharedData
public T2 MyProperty1 { get; set; }
}
[MessagePackObject]
public class GenericConstrainedClassIntKey<T1, T2>
where T1 : class
where T2 : class, IEqualityComparer<T1>
{
[Key(0)]
public T1 MyProperty0 { get; set; }
[Key(1)]
public T2 Comparer { get; set; }
}
[MessagePackObject(keyAsPropertyName: true)]
public class GenericConstrainedClassStringKey<T1, T2>
where T1 : class
where T2 : class, IEqualityComparer<T1>
{
public T1 MyProperty0 { get; set; }
public T2 Comparer { get; set; }
}
[MessagePackObject]
public struct GenericConstrainedStructIntKey<T1, T2>
where T1 : unmanaged
where T2 : unmanaged, IEqualityComparer<T1>
{
[Key(0)]
public T1 MyProperty0 { get; set; }
[Key(1)]
public T2 Comparer { get; set; }
}
[MessagePackObject(keyAsPropertyName: true)]
public struct GenericConstrainedStructStringKey<T1, T2>
where T1 : unmanaged
where T2 : unmanaged, IEqualityComparer<T1>
{
public T1 MyProperty0 { get; set; }
public T2 Comparer { get; set; }
}
[MessagePackObject]
public class VersionBlockTest
{

Просмотреть файл

@ -6,6 +6,7 @@
using System;
using System.Runtime.Serialization;
using MessagePack.Resolvers;
using Nerdbank.Streams;
using Xunit;
using Xunit.Abstractions;
@ -45,6 +46,95 @@ namespace MessagePack.Tests
PrivateMembersInBaseClass_Helper(options);
}
[Fact]
public void DeserializerSetsMissingPropertiesToDefaultValue()
{
var seq = new Sequence<byte>();
var writer = new MessagePackWriter(seq);
writer.WriteMapHeader(1);
writer.Write(nameof(TwoProperties.Prop1));
writer.Write("Set");
writer.Flush();
var instance = MessagePackSerializer.Deserialize<TwoProperties>(seq);
Assert.Equal("Set", instance.Prop1);
Assert.Null(instance.Prop2);
}
[Fact]
public void DeserializerSetsMissingPropertiesToDefaultValue_OrdinalKey()
{
var seq = new Sequence<byte>();
var writer = new MessagePackWriter(seq);
writer.WriteArrayHeader(1);
writer.Write("Set");
writer.Flush();
var instance = MessagePackSerializer.Deserialize<TwoPropertiesOrdinalKey>(seq);
Assert.Equal("Set", instance.Prop1);
Assert.Null(instance.Prop2);
}
/// <summary>
/// Verifies that virtual and overridden properties do not cause the dynamic resolver to malfunction.
/// </summary>
[Fact]
public void VirtualOverriddenProperties()
{
var obj = new DerivedClassThatOverridesProperty { VirtualProperty = 100 };
byte[] bin = MessagePackSerializer.Serialize(obj);
var obj2 = MessagePackSerializer.Deserialize<DerivedClassThatOverridesProperty>(bin);
Assert.Equal(obj.VirtualProperty, obj2.VirtualProperty);
}
[Fact]
public void VirtualOverriddenProperties_DataMemberOnBase()
{
var obj = new DerivedClassThatOverridesPropertyDataMemberOnVirtualOnly { VirtualProperty = 100 };
byte[] bin = MessagePackSerializer.Serialize(obj);
var obj2 = MessagePackSerializer.Deserialize<DerivedClassThatOverridesPropertyDataMemberOnVirtualOnly>(bin);
Assert.Equal(obj.VirtualProperty, obj2.VirtualProperty);
}
[Fact]
public void VirtualOverriddenProperties_DataMemberOnOverride()
{
var obj = new DerivedClassThatOverridesPropertyDataMemberOnOverrideOnly { VirtualProperty = 100 };
byte[] bin = MessagePackSerializer.Serialize(obj);
var obj2 = MessagePackSerializer.Deserialize<DerivedClassThatOverridesPropertyDataMemberOnOverrideOnly>(bin);
Assert.Equal(obj.VirtualProperty, obj2.VirtualProperty);
}
/// <summary>
/// Verifies that virtual and overridden properties do not cause the dynamic resolver to malfunction.
/// </summary>
[Fact]
public void VirtualOverriddenProperties_OrdinalKey()
{
var obj = new DerivedClassThatOverridesPropertyOrdinalKey { VirtualProperty = 100 };
byte[] bin = MessagePackSerializer.Serialize(obj);
var obj2 = MessagePackSerializer.Deserialize<DerivedClassThatOverridesPropertyOrdinalKey>(bin);
Assert.Equal(obj.VirtualProperty, obj2.VirtualProperty);
}
[Fact]
public void VirtualOverriddenProperties_DataMemberOnBase_OrdinalKey()
{
var obj = new DerivedClassThatOverridesPropertyDataMemberOnVirtualOnlyOrdinalKey { VirtualProperty = 100 };
byte[] bin = MessagePackSerializer.Serialize(obj);
var obj2 = MessagePackSerializer.Deserialize<DerivedClassThatOverridesPropertyDataMemberOnVirtualOnlyOrdinalKey>(bin);
Assert.Equal(obj.VirtualProperty, obj2.VirtualProperty);
}
[Fact]
public void VirtualOverriddenProperties_DataMemberOnOverride_OrdinalKey()
{
var obj = new DerivedClassThatOverridesPropertyDataMemberOnOverrideOnlyOrdinalKey { VirtualProperty = 100 };
byte[] bin = MessagePackSerializer.Serialize(obj);
var obj2 = MessagePackSerializer.Deserialize<DerivedClassThatOverridesPropertyDataMemberOnOverrideOnlyOrdinalKey>(bin);
Assert.Equal(obj.VirtualProperty, obj2.VirtualProperty);
}
private static void Assert3MemberClassSerializedContent(ReadOnlyMemory<byte> msgpack)
{
var reader = new MessagePackReader(msgpack);
@ -65,6 +155,130 @@ namespace MessagePack.Tests
Assert.Equal(obj.Name, obj2.Name);
}
[DataContract]
public class BaseClassWithVirtualProperty
{
[DataMember]
public virtual int VirtualProperty { get; set; }
}
[DataContract]
public class DerivedClassThatOverridesProperty : BaseClassWithVirtualProperty
{
[DataMember]
public override int VirtualProperty
{
get => base.VirtualProperty;
set => base.VirtualProperty = value;
}
}
[DataContract]
public class BaseClassWithVirtualPropertyDataMemberOnOverrideOnly
{
public virtual int VirtualProperty { get; set; }
}
[DataContract]
public class DerivedClassThatOverridesPropertyDataMemberOnOverrideOnly : BaseClassWithVirtualPropertyDataMemberOnOverrideOnly
{
[DataMember]
public override int VirtualProperty
{
get => base.VirtualProperty;
set => base.VirtualProperty = value;
}
}
[DataContract]
public class BaseClassWithVirtualPropertyDataMemberOnVirtualOnly
{
[DataMember]
public virtual int VirtualProperty { get; set; }
}
[DataContract]
public class DerivedClassThatOverridesPropertyDataMemberOnVirtualOnly : BaseClassWithVirtualPropertyDataMemberOnVirtualOnly
{
public override int VirtualProperty
{
get => base.VirtualProperty;
set => base.VirtualProperty = value;
}
}
[DataContract]
public class BaseClassWithVirtualPropertyOrdinalKey
{
[DataMember(Order = 0)]
public virtual int VirtualProperty { get; set; }
}
[DataContract]
public class DerivedClassThatOverridesPropertyOrdinalKey : BaseClassWithVirtualPropertyOrdinalKey
{
[DataMember(Order = 0)]
public override int VirtualProperty
{
get => base.VirtualProperty;
set => base.VirtualProperty = value;
}
}
[DataContract]
public class BaseClassWithVirtualPropertyDataMemberOnOverrideOnlyOrdinalKey
{
public virtual int VirtualProperty { get; set; }
}
[DataContract]
public class DerivedClassThatOverridesPropertyDataMemberOnOverrideOnlyOrdinalKey : BaseClassWithVirtualPropertyDataMemberOnOverrideOnlyOrdinalKey
{
[DataMember(Order = 0)]
public override int VirtualProperty
{
get => base.VirtualProperty;
set => base.VirtualProperty = value;
}
}
[DataContract]
public class BaseClassWithVirtualPropertyDataMemberOnVirtualOnlyOrdinalKey
{
[DataMember(Order = 0)]
public virtual int VirtualProperty { get; set; }
}
[DataContract]
public class DerivedClassThatOverridesPropertyDataMemberOnVirtualOnlyOrdinalKey : BaseClassWithVirtualPropertyDataMemberOnVirtualOnlyOrdinalKey
{
public override int VirtualProperty
{
get => base.VirtualProperty;
set => base.VirtualProperty = value;
}
}
[DataContract]
public class TwoProperties
{
[DataMember]
public string Prop1 { get; set; } = "Uninitialized";
[DataMember]
public string Prop2 { get; set; } = "Uninitialized";
}
[DataContract]
public class TwoPropertiesOrdinalKey
{
[DataMember(Order = 0)]
public string Prop1 { get; set; } = "Uninitialized";
[DataMember(Order = 1)]
public string Prop2 { get; set; } = "Uninitialized";
}
[MessagePackObject]
public class TestMessageWithReadOnlyField
{