Skip to content

Commit fd8145f

Browse files
committed
Enable customizing the property serialization condition in PropertyCSScriptSerializer
1 parent 22adb15 commit fd8145f

File tree

4 files changed

+39
-80
lines changed

4 files changed

+39
-80
lines changed

src/CSharpScriptSerializer/PropertyCSScriptSerializer.cs

Lines changed: 27 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -13,84 +13,54 @@ public class PropertyCSScriptSerializer<T> : ConstructorCSScriptSerializer<T>
1313
private readonly IReadOnlyCollection<PropertyData> _propertyData;
1414

1515
public PropertyCSScriptSerializer()
16-
: this((Func<T, object>[])null)
16+
: this((Func<T, object>[]) null)
1717
{
1818
}
1919

20-
public PropertyCSScriptSerializer(IReadOnlyCollection<Func<T, object>> argumentGetters)
21-
: this(typeof(T).GetRuntimeProperties().Where(IsCandidateProperty), argumentGetters)
20+
public PropertyCSScriptSerializer(IReadOnlyCollection<Func<T, object>> constructorParameterGetters)
21+
: this(propertyConditions: null, constructorParameterGetters: constructorParameterGetters)
2222
{
2323
}
2424

25-
public PropertyCSScriptSerializer(IEnumerable<PropertyInfo> properties)
26-
: this(properties, constructorParameterGetters: null)
25+
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object, bool>> propertyConditions)
26+
: this(propertyConditions, constructorParameterGetters: null)
2727
{
2828
}
2929

30-
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object>> propertyValueGetters)
31-
: this(propertyValueGetters, constructorParameterGetters: null)
32-
{
33-
}
34-
35-
public PropertyCSScriptSerializer(IEnumerable<PropertyInfo> properties,
30+
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object, bool>> propertyConditions,
3631
IReadOnlyCollection<Func<T, object>> constructorParameterGetters)
37-
: this(properties.Select(p => new PropertyData(
38-
p.Name,
39-
p.PropertyType,
40-
CreatePropertyInitializer(p),
41-
o => GetDefault(p.PropertyType))).ToArray(),
42-
constructorParameterGetters)
43-
{
44-
}
45-
46-
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object>> propertyValueGetters,
47-
IReadOnlyCollection<Func<T, object>> constructorParameterGetters)
48-
: this(propertyValueGetters, constructorParameterGetters, new Dictionary<string, object>())
49-
{
50-
}
51-
52-
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object>> propertyValueGetters,
53-
IReadOnlyCollection<Func<T, object>> constructorParameterGetters,
54-
IReadOnlyDictionary<string, object> propertyDefaults)
55-
: this(
56-
propertyValueGetters,
57-
constructorParameterGetters,
58-
propertyDefaults.ToDictionary<KeyValuePair<string, object>, string, Func<T, object>>(
59-
p => p.Key,
60-
p => o => p.Value))
32+
: this(propertyConditions, constructorParameterGetters, propertyValueGetters: null)
6133
{
6234
}
6335

64-
// To not serialize properties give default that's always equal to the property value
65-
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object>> propertyValueGetters,
36+
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object, bool>> propertyConditions,
6637
IReadOnlyCollection<Func<T, object>> constructorParameterGetters,
67-
IReadOnlyDictionary<string, Func<T, object>> propertyDefaultGetters)
68-
: this(constructorParameterGetters)
38+
IReadOnlyDictionary<string, Func<T, object>> propertyValueGetters)
39+
: base(constructorParameterGetters)
6940
{
70-
var referencedProperties = typeof(T).GetTypeInfo()
41+
propertyConditions = propertyConditions ?? new Dictionary<string, Func<T, object, bool>>();
42+
propertyValueGetters = propertyValueGetters ?? new Dictionary<string, Func<T, object>>();
43+
var referencedPropertyNames = propertyConditions.Keys.Concat(propertyValueGetters.Keys).Distinct();
44+
var allProperties = typeof(T).GetTypeInfo()
7145
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
72-
.Where(p => propertyValueGetters.ContainsKey(p.Name));
73-
_propertyData = typeof(T).GetRuntimeProperties().Where(IsCandidateProperty)
74-
.Concat(referencedProperties).Distinct().Select(
46+
.ToDictionary(p => p.Name);
47+
48+
_propertyData = referencedPropertyNames.Select(n => allProperties[n])
49+
.Concat(allProperties.Values.Where(IsCandidateProperty)).Distinct()
50+
.Select(
7551
p => new PropertyData(
7652
p.Name,
7753
p.PropertyType,
7854
propertyValueGetters.GetValueOrDefault(p.Name, CreatePropertyInitializer(p)),
79-
propertyDefaultGetters.GetValueOrDefault(p.Name, o => GetDefault(p.PropertyType))))
55+
propertyConditions.GetValueOrDefault(p.Name,
56+
(o, v) => !Equals(v, GetDefault(p.PropertyType)))))
8057
.ToArray();
8158
}
8259

83-
protected PropertyCSScriptSerializer(IReadOnlyCollection<PropertyData> propertyData,
84-
IReadOnlyCollection<Func<T, object>> constructorParameterGetters)
85-
: base(constructorParameterGetters)
86-
{
87-
_propertyData = propertyData;
88-
}
89-
9060
protected override bool GenerateEmptyArgumentList => false;
9161

9262
public override ExpressionSyntax GetCreation(object obj)
93-
=> GetObjectCreationExpression((T)obj);
63+
=> GetObjectCreationExpression((T) obj);
9464

9565
protected override ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
9666
=> base.GetObjectCreationExpression(obj)
@@ -99,18 +69,11 @@ protected override ObjectCreationExpressionSyntax GetObjectCreationExpression(T
9969
SyntaxKind.ObjectInitializerExpression,
10070
SyntaxFactory.SeparatedList<ExpressionSyntax>(
10171
ToCommaSeparatedList(_propertyData
102-
.Select(p => new
103-
{
104-
p.PropertyName,
105-
p.PropertyType,
106-
PropertyValue = p.PropertyValueGetter(obj),
107-
PropertyDefault = p.PropertyDefaultGetter(obj)
108-
})
109-
.Where(p => !Equals(p.PropertyValue, p.PropertyDefault))
72+
.Where(p => p.PropertyCondition(obj, p.PropertyValueGetter(obj)))
11073
.Select(p => SyntaxFactory.AssignmentExpression(
11174
SyntaxKind.SimpleAssignmentExpression,
11275
SyntaxFactory.IdentifierName(p.PropertyName),
113-
GetCreationExpression(p.PropertyValue))))))));
76+
GetCreationExpression(p.PropertyValueGetter(obj)))))))));
11477

11578
protected static Func<T, object> CreatePropertyInitializer(PropertyInfo property)
11679
{
@@ -129,18 +92,18 @@ public PropertyData(
12992
string propertyName,
13093
Type propertyType,
13194
Func<T, object> propertyValueGetter,
132-
Func<T, object> propertyDefaultGetter)
95+
Func<T, object, bool> propertyCondition)
13396
{
13497
PropertyName = propertyName;
13598
PropertyType = propertyType;
13699
PropertyValueGetter = propertyValueGetter;
137-
PropertyDefaultGetter = propertyDefaultGetter;
100+
PropertyCondition = propertyCondition;
138101
}
139102

140103
public string PropertyName { get; }
141104
public Type PropertyType { get; }
142105
public Func<T, object> PropertyValueGetter { get; }
143-
public Func<T, object> PropertyDefaultGetter { get; }
106+
public Func<T, object, bool> PropertyCondition { get; }
144107
}
145108
}
146109
}

src/CSharpScriptSerializer/project.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "1.0.0-*",
2+
"version": "1.1.0-*",
33
"name": "CSharpScriptSerializer",
44
"title": "CSharpScriptSerializer",
55
"description": "Serialize to C# scripts",
@@ -9,7 +9,7 @@
99
"packOptions": {
1010
"tags": [ "Roslyn", "CSharp", "C#", "CSX", "Script", "Serialization" ],
1111
"owners": [ "Andriy.Svyryd" ],
12-
"releaseNotes": "Version 1.0.0\r\n* Enable customizing the default values in PropertyCSScriptSerializer\r\n* Change ICSScriptSerializable.GetSerializer() to return ICSScriptSerializer\r\n* Fix parameters not being used in DeserializeAsync\r\n\r\nVersion 1.0.0-alpha1\r\n* Initial release",
12+
"releaseNotes": "Version 1.1.0\r\n* Enable customizing the property serialization condition in PropertyCSScriptSerializer\r\nVersion 1.0.0\r\n* Enable customizing the default values in PropertyCSScriptSerializer\r\n* Change ICSScriptSerializable.GetSerializer() to return ICSScriptSerializer\r\n* Fix parameters not being used in DeserializeAsync\r\n\r\nVersion 1.0.0-alpha1\r\n* Initial release",
1313
"projectUrl": "https://github.com/AndriySvyryd/CSharpScriptSerializer",
1414
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0",
1515
"requireLicenseAcceptance": false,

test/CSharpScriptSerializer.Tests/RoundTrippingTest.cs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -229,10 +229,6 @@ public SerializableConstructor(string requiredString)
229229

230230
public ICSScriptSerializer GetSerializer()
231231
=> new PropertyCSScriptSerializer<SerializableConstructor>(
232-
new Dictionary<string, Func<SerializableConstructor, object>>
233-
{
234-
{nameof(OptionalInt), o => o.OptionalInt}
235-
},
236232
new List<Func<SerializableConstructor, object>> {o => o.RequiredString});
237233
}
238234

@@ -258,9 +254,9 @@ public void CustomSerializer()
258254
CSScriptSerializer.Serializers.TryRemove(typeof(ConstructorParams), out _);
259255
CSScriptSerializer.Serializers[typeof(ConstructorParams)] =
260256
new PropertyCSScriptSerializer<ConstructorParams>(
261-
new Dictionary<string, Func<ConstructorParams, object>>
257+
new Dictionary<string, Func<ConstructorParams, object, bool>>
262258
{
263-
{nameof(ConstructorParams.OptionalInt), o => o.OptionalInt}
259+
{nameof(ConstructorParams.OptionalInt), (o, v) => v != null}
264260
},
265261
new List<Func<ConstructorParams, object>> {o => o.RequiredString});
266262

@@ -291,32 +287,32 @@ public class ConstructorParamsSerializerFactory : ICSScriptSerializerFactory
291287
public ICSScriptSerializer TryCreate(Type type)
292288
=> type == typeof(ConstructorParams)
293289
? new PropertyCSScriptSerializer<ConstructorParams>(
294-
new Dictionary<string, Func<ConstructorParams, object>>
290+
new Dictionary<string, Func<ConstructorParams, object, bool>>
295291
{
296-
{nameof(ConstructorParams.OptionalInt), o => o.OptionalInt}
292+
{nameof(ConstructorParams.OptionalInt), (o, v) => true}
297293
},
298294
new List<Func<ConstructorParams, object>> {o => o.RequiredString})
299295
: null;
300296
}
301297

302298
[Fact]
303-
public void PropertyCSScriptSerializer_can_use_custom_defaults()
299+
public void PropertyCSScriptSerializer_can_use_custom_values_and_defaults()
304300
{
305301
ICSScriptSerializer _;
306302
CSScriptSerializer.Serializers.TryRemove(typeof(ConstructorParams), out _);
307303
CSScriptSerializer.Serializers[typeof(ConstructorParams)] =
308304
new PropertyCSScriptSerializer<ConstructorParams>(
309-
new Dictionary<string, Func<ConstructorParams, object>>
305+
new Dictionary<string, Func<ConstructorParams, object, bool>>
310306
{
311-
{nameof(ConstructorParams.OptionalInt), o => o.OptionalInt}
307+
{nameof(ConstructorParams.OptionalInt), (o, v) => (int?) v != 1}
312308
},
313309
new List<Func<ConstructorParams, object>> {o => o.RequiredString},
314310
new Dictionary<string, Func<ConstructorParams, object>>
315311
{
316312
{nameof(ConstructorParams.OptionalInt), o => 1}
317313
});
318314

319-
var input = new ConstructorParams("s") { OptionalInt = 1 };
315+
var input = new ConstructorParams("s") { OptionalInt = 2 };
320316
var script = CSScriptSerializer.Serialize(input);
321317
var output = CSScriptSerializer.Deserialize<ConstructorParams>(script);
322318

test/CSharpScriptSerializer.Tests/project.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "1.0.0-*",
2+
"version": "1.1.0-*",
33

44
"buildOptions": {
55
"warningsAsErrors": true
@@ -8,7 +8,7 @@
88
"testRunner": "xunit",
99

1010
"dependencies": {
11-
"CSharpScriptSerializer": "1.0.0-*",
11+
"CSharpScriptSerializer": "1.1.0-*",
1212
"dotnet-test-xunit": "2.2.0-preview2-build1029",
1313
"xunit": "2.2.0-beta4-build3444"
1414
},

0 commit comments

Comments
 (0)