Skip to content

Commit 3162562

Browse files
committed
Add attr to not overwrite Member with default value
1 parent aa947b3 commit 3162562

6 files changed

Lines changed: 62 additions & 48 deletions

File tree

src/MemoryPack.Core/Attributes.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,6 @@ public sealed class MemoryPackOnDeserializedAttribute : Attribute
153153
public sealed class GenerateTypeScriptAttribute : Attribute
154154
{
155155
}
156+
157+
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
158+
public sealed class SkipOverwriteByDefaultAttribute : Attribute;

src/MemoryPack.Generator/MemoryPackGenerator.Emitter.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -539,14 +539,15 @@ private string EmitDeserializeBody()
539539
540540
SET:
541541
{{(!IsUseEmptyConstructor ? "goto NEW;" : "")}}
542-
{{Members.Where(x => x.Symbol != null).Where(x => x.IsAssignable).Select(x => $" {(IsUseEmptyConstructor ? "" : "// ")}value.@{x.Name} = __{x.Name};").NewLine()}}
542+
{{Members.Where(x => x.IsAssignable).Select(x => $" {(IsUseEmptyConstructor ? "" : "// ")}value.@{x.Name} = __{x.Name};").NewLine()}}
543543
goto READ_END;
544544
545545
NEW:
546546
value = {{EmitConstructor()}}
547547
{
548548
{{EmitDeserializeConstruction(" ")}}
549549
};
550+
{{Members.Select((x, i) => (x, i)).Where(v => v.x.SkipOverwriteByDefault && v.x.IsAssignable).Select(v => $" if ({v.i + 1} <= count) value.@{v.x.Name} = __{v.x.Name};").NewLine()}}
550551
READ_END:
551552
{{readEndBody}}
552553
""";
@@ -916,7 +917,7 @@ string EmitDeserializeConstruction(string indent)
916917
{
917918
// all value is deserialized, __Name is exsits.
918919
return string.Join("," + Environment.NewLine, Members
919-
.Where(x => x.IsSettable && !x.IsConstructorParameter)
920+
.Where(x => x is { IsSettable: true, IsConstructorParameter: false, SkipOverwriteByDefault: false })
920921
.Select(x => $"{indent}@{x.Name} = __{x.Name}"));
921922
}
922923

src/MemoryPack.Generator/MemoryPackGenerator.Parser.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ partial class MemberMeta
615615
public int Order { get; }
616616
public bool HasExplicitOrder { get; }
617617
public MemberKind Kind { get; }
618+
public bool SkipOverwriteByDefault { get; }
618619

619620
MemberMeta(int order)
620621
{
@@ -630,6 +631,7 @@ public MemberMeta(ISymbol symbol, IMethodSymbol? constructor, ReferenceSymbols r
630631
this.Symbol = symbol;
631632
this.Name = symbol.Name;
632633
this.Order = sequentialOrder;
634+
this.SkipOverwriteByDefault = symbol.ContainsAttribute(references.SkipOverwriteDefaultAttribute);
633635
var orderAttr = symbol.GetAttribute(references.MemoryPackOrderAttribute);
634636
if (orderAttr != null)
635637
{

src/MemoryPack.Generator/ReferenceSymbols.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ public class ReferenceSymbols
2222
public INamedTypeSymbol MemoryPackOnSerializedAttribute { get; }
2323
public INamedTypeSymbol MemoryPackOnDeserializingAttribute { get; }
2424
public INamedTypeSymbol MemoryPackOnDeserializedAttribute { get; }
25+
public INamedTypeSymbol SkipOverwriteDefaultAttribute { get; }
2526
public INamedTypeSymbol GenerateTypeScriptAttribute { get; }
2627
public INamedTypeSymbol IMemoryPackable { get; }
2728

@@ -46,6 +47,7 @@ public ReferenceSymbols(Compilation compilation)
4647
MemoryPackOnSerializedAttribute = GetTypeByMetadataName("MemoryPack.MemoryPackOnSerializedAttribute");
4748
MemoryPackOnDeserializingAttribute = GetTypeByMetadataName("MemoryPack.MemoryPackOnDeserializingAttribute");
4849
MemoryPackOnDeserializedAttribute = GetTypeByMetadataName("MemoryPack.MemoryPackOnDeserializedAttribute");
50+
SkipOverwriteDefaultAttribute = GetTypeByMetadataName("MemoryPack.SkipOverwriteByDefaultAttribute");
4951
GenerateTypeScriptAttribute = GetTypeByMetadataName(MemoryPackGenerator.GenerateTypeScriptAttributeFullName);
5052
IMemoryPackable = GetTypeByMetadataName("MemoryPack.IMemoryPackable`1").ConstructUnboundGenericType();
5153
KnownTypes = new WellKnownTypes(this);
@@ -161,7 +163,7 @@ public class WellKnownTypes
161163

162164
{ "System.Collections.Generic.KeyValuePair<,>", "global::MemoryPack.Formatters.KeyValuePairFormatter<TREPLACE>" },
163165
{ "System.Lazy<>", "global::MemoryPack.Formatters.LazyFormatter<TREPLACE>" },
164-
166+
165167
// TupleFormatters
166168
{ "System.Tuple<>", "global::MemoryPack.Formatters.TupleFormatter<TREPLACE>" },
167169
{ "System.Tuple<,>", "global::MemoryPack.Formatters.TupleFormatter<TREPLACE>" },
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using MemoryPack.Tests.Models;
2+
3+
namespace MemoryPack.Tests;
4+
5+
public class DefaultValueTest
6+
{
7+
[Fact]
8+
public void FieldDefaultValue()
9+
{
10+
var bin = MemoryPackSerializer.Serialize(new DefaultValuePlaceholder { X = 1 });
11+
var expected = new FieldDefaultValue();
12+
var deserializedValue = MemoryPackSerializer.Deserialize<FieldDefaultValue>(bin)!;
13+
deserializedValue.Y.Should().Be(default);
14+
deserializedValue.Z.Should().Be(expected.Z);
15+
deserializedValue.FromMethod.Should().Be(expected.FromMethod);
16+
}
17+
18+
[Fact]
19+
public void PropertyDefaultValue()
20+
{
21+
var bin = MemoryPackSerializer.Serialize(new DefaultValuePlaceholder { X = 1 });
22+
var expected = new PropertyDefaultValue();
23+
var deserializedValue = MemoryPackSerializer.Deserialize<PropertyDefaultValue>(bin)!;
24+
deserializedValue.Y.Should().Be(default);
25+
deserializedValue.Z.Should().Be(expected.Z);
26+
deserializedValue.FromMethod.Should().Be(expected.FromMethod);
27+
}
28+
}
Lines changed: 23 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,47 @@
1-
using System;
2-
using System.Collections.Generic;
3-
41
namespace MemoryPack.Tests.Models;
52

6-
enum TestEnum
7-
{
8-
A, B, C
9-
}
10-
113
[MemoryPackable]
124
partial class DefaultValuePlaceholder
135
{
146
public int X { get; set; }
157
}
168

9+
static class StaticMethod
10+
{
11+
public static int GetNumberCalls;
12+
13+
public static int GetNumber()
14+
{
15+
GetNumberCalls++;
16+
return 100;
17+
}
18+
}
19+
1720
[MemoryPackable]
1821
partial class FieldDefaultValue
1922
{
2023
public int X;
2124
public int Y = 12345;
25+
26+
[SkipOverwriteByDefault]
2227
public float Z = 678.9f;
23-
public string S = "aaaaaaaaa";
24-
public bool B = true;
28+
29+
[SkipOverwriteByDefault]
30+
public int FromMethod = StaticMethod.GetNumber();
2531
}
2632

2733
[MemoryPackable]
2834
partial class PropertyDefaultValue
2935
{
30-
internal enum NestedEnum
31-
{
32-
A, B
33-
}
34-
35-
public int X { get; set; }
36+
public int X { get; init; }
3637
public int Y { get; set; } = 12345;
38+
39+
[SkipOverwriteByDefault]
3740
public float Z { get; set; } = 678.9f;
38-
public string S { get; set; } = "aaaaaaaaa";
39-
public bool B { get; set; } = true;
40-
public List<string> Alpha { get; set; } = new List<string>(new HashSet<string>());
41-
public TestEnum E { get; set; } = TestEnum.A;
42-
public NestedEnum E2 { get; set; } = NestedEnum.A;
43-
public (TestEnum, List<string>) Tuple { get; set; } = (TestEnum.A, new List<string>(new HashSet<string>()));
44-
public DateTime Struct { get; set; } = default!;
45-
}
4641

47-
[MemoryPackable]
48-
partial class CtorParamDefaultValue
49-
{
50-
public int X;
51-
public int Y;
52-
public float Z;
53-
public string S;
54-
public bool B;
55-
public decimal D;
56-
public DateTime StructValue;
42+
[SkipOverwriteByDefault]
43+
public float W { get; init; } = 678.9f;
5744

58-
[MemoryPackConstructor]
59-
public CtorParamDefaultValue(int x, int y = 12345, float z = 678.9f, string s = "aaaaaa", bool b = true, decimal d = 99M, DateTime structValue = default)
60-
{
61-
X = x;
62-
Y = y;
63-
Z = z;
64-
S = s;
65-
B = b;
66-
D = d;
67-
StructValue = structValue;
68-
}
45+
[SkipOverwriteByDefault]
46+
public int FromMethod { get; set; } = StaticMethod.GetNumber();
6947
}

0 commit comments

Comments
 (0)