Skip to content

Commit 214cecb

Browse files
committed
Enable customizing the default values in PropertyCSScriptSerializer
Change ICSScriptSerializable.GetSerializer() to return ICSScriptSerializer Fix parameters not being used in DeserializeAsync Don't use dynamic dispatch in LiteralCSScriptSerializer
1 parent 8a2421b commit 214cecb

File tree

11 files changed

+175
-60
lines changed

11 files changed

+175
-60
lines changed

global.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"projects": [ "src", "test" ],
33
"sdk": {
4-
"version": "1.0.0-preview2-003131"
4+
"version": "1.0.0-preview2-1-003177"
55
}
66
}

src/CSharpScriptSerializer/CSScriptSerializer.cs

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ public static Task<T> DeserializeAsync<T>(string script)
4141
public static T Deserialize<T>(string script, IEnumerable<Assembly> referencedAssemblies, IEnumerable<string> imports)
4242
=> DeserializeAsync<T>(script, referencedAssemblies, imports).GetAwaiter().GetResult();
4343

44-
public static Task<T> DeserializeAsync<T>(string script, IEnumerable<Assembly> referencedAssemblies, IEnumerable<string> imports)
44+
public static Task<T> DeserializeAsync<T>(
45+
string script, IEnumerable<Assembly> referencedAssemblies, IEnumerable<string> imports)
4546
=> CSharpScript.EvaluateAsync<T>(script,
4647
ScriptOptions.Default.WithReferences(
4748
typeof(T).GetTypeInfo().Assembly,
@@ -53,10 +54,12 @@ public static Task<T> DeserializeAsync<T>(string script, IEnumerable<Assembly> r
5354
.AddReferences(typeof(CSScriptSerializer).GetTypeInfo()
5455
.Assembly.GetReferencedAssemblies()
5556
.Select(Assembly.Load))
57+
.AddReferences(referencedAssemblies)
5658
.AddImports(
5759
typeof(T).GetTypeInfo().Namespace,
5860
typeof(DateTime).GetTypeInfo().Namespace,
59-
typeof(List<>).GetTypeInfo().Namespace));
61+
typeof(List<>).GetTypeInfo().Namespace)
62+
.AddImports(imports));
6063

6164
public static string Serialize(object obj)
6265
{
@@ -80,10 +83,7 @@ public static CompilationUnitSyntax GetCompilationUnitExpression(object obj)
8083

8184
public static ExpressionSyntax GetCreationExpression(object obj)
8285
{
83-
var serializable = obj as ICSScriptSerializable;
84-
return serializable != null
85-
? serializable.GetCreation()
86-
: GetSerializer(obj).GetCreation(obj);
86+
return GetSerializer(obj).GetCreation(obj);
8787
}
8888

8989
private static ICSScriptSerializer GetSerializer(object obj)
@@ -93,6 +93,12 @@ private static ICSScriptSerializer GetSerializer(object obj)
9393
return NullCSScriptSerializer.Instance;
9494
}
9595

96+
var serializable = obj as ICSScriptSerializable;
97+
if (serializable != null)
98+
{
99+
return serializable.GetSerializer();
100+
}
101+
96102
var type = UnwrapNullableType(obj.GetType());
97103
if (type == typeof(bool))
98104
{
@@ -238,7 +244,6 @@ private static ICSScriptSerializer CreateSerializer(Type type)
238244
throw new InvalidOperationException($"The type {type} does not have public writable properties");
239245
}
240246

241-
// TODO: record types being constructed to avoid recursion
242247
return (CSScriptSerializer)GetDeclaredConstructor(
243248
typeof(PropertyCSScriptSerializer<>).MakeGenericType(type), types: null)
244249
.Invoke(parameters: null);

src/CSharpScriptSerializer/CollectionCSScriptSerializer.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,19 @@ public class CollectionCSScriptSerializer<T> : ConstructorCSScriptSerializer<T>
1313
private readonly Func<T, IEnumerable<object>> _getEnumerable;
1414

1515
public CollectionCSScriptSerializer()
16-
: this(elementDecomposers: null, parameterGetters: null)
16+
: this(elementDecomposers: null, constructorParameterGetters: null)
1717
{
1818
}
1919

2020
public CollectionCSScriptSerializer(
2121
IReadOnlyCollection<Func<object, object>> elementDecomposers)
22-
: this(elementDecomposers, parameterGetters: null)
22+
: this(elementDecomposers, constructorParameterGetters: null)
2323
{
2424
}
2525

2626
public CollectionCSScriptSerializer(
27-
IReadOnlyCollection<Func<T, object>> parameterGetters)
28-
: this(elementDecomposers: null, parameterGetters: parameterGetters)
27+
IReadOnlyCollection<Func<T, object>> constructorParameterGetters)
28+
: this(elementDecomposers: null, constructorParameterGetters: constructorParameterGetters)
2929
{
3030
}
3131

@@ -37,9 +37,9 @@ public CollectionCSScriptSerializer(
3737
}
3838

3939
public CollectionCSScriptSerializer(
40-
IReadOnlyCollection<Func<T, object>> parameterGetters,
40+
IReadOnlyCollection<Func<T, object>> constructorParameterGetters,
4141
Func<T, IEnumerable<object>> getEnumerable)
42-
: this(elementDecomposers: null, parameterGetters: parameterGetters, getEnumerable: getEnumerable)
42+
: this(elementDecomposers: null, constructorParameterGetters: constructorParameterGetters, getEnumerable: getEnumerable)
4343
{
4444
}
4545

@@ -52,8 +52,8 @@ public CollectionCSScriptSerializer(
5252

5353
public CollectionCSScriptSerializer(
5454
IReadOnlyCollection<Func<object, object>> elementDecomposers,
55-
IReadOnlyCollection<Func<T, object>> parameterGetters)
56-
: this(elementDecomposers, parameterGetters, getEnumerable: null)
55+
IReadOnlyCollection<Func<T, object>> constructorParameterGetters)
56+
: this(elementDecomposers, constructorParameterGetters, getEnumerable: null)
5757
{
5858
}
5959

@@ -71,9 +71,9 @@ public CollectionCSScriptSerializer(
7171

7272
public CollectionCSScriptSerializer(
7373
IReadOnlyCollection<Func<object, object>> elementDecomposers,
74-
IReadOnlyCollection<Func<T, object>> parameterGetters,
74+
IReadOnlyCollection<Func<T, object>> constructorParameterGetters,
7575
Func<T, IEnumerable<object>> getEnumerable)
76-
: base(parameterGetters)
76+
: base(constructorParameterGetters)
7777
{
7878
_elementDecomposers = elementDecomposers;
7979
_getEnumerable = getEnumerable ?? (o => ((IEnumerable)o).Cast<object>());

src/CSharpScriptSerializer/ConstructorCSScriptSerializer.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ namespace CSharpScriptSerialization
99
public class ConstructorCSScriptSerializer<T> : CSScriptSerializer
1010
{
1111
private ObjectCreationExpressionSyntax _objectCreationExpression;
12-
private readonly IReadOnlyCollection<Func<T, object>> _parameterGetters;
12+
private readonly IReadOnlyCollection<Func<T, object>> _constructorParameterGetters;
1313

1414
public ConstructorCSScriptSerializer()
15-
: this(parameterGetters: null)
15+
: this(constructorParameterGetters: null)
1616
{
1717
}
1818

@@ -22,27 +22,27 @@ public ConstructorCSScriptSerializer(IReadOnlyCollection<Func<object, object>> n
2222
{
2323
}
2424

25-
public ConstructorCSScriptSerializer(IReadOnlyCollection<Func<T, object>> parameterGetters)
25+
public ConstructorCSScriptSerializer(IReadOnlyCollection<Func<T, object>> constructorParameterGetters)
2626
: base(typeof(T))
2727
{
28-
_parameterGetters = parameterGetters;
28+
_constructorParameterGetters = constructorParameterGetters;
2929
}
3030

3131
protected virtual bool GenerateEmptyArgumentList => true;
3232

3333
public override ExpressionSyntax GetCreation(object obj) => GetObjectCreationExpression((T)obj);
3434

3535
protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
36-
=> _parameterGetters == null
37-
|| _parameterGetters.Count == 0
36+
=> _constructorParameterGetters == null
37+
|| _constructorParameterGetters.Count == 0
3838
? GenerateEmptyArgumentList
3939
? GetObjectCreationExpression().WithArgumentList(SyntaxFactory.ArgumentList())
4040
: GetObjectCreationExpression()
4141
: GetObjectCreationExpression()
4242
.WithArgumentList(AddNewLine(SyntaxFactory.ArgumentList(
4343
SyntaxFactory.SeparatedList<ArgumentSyntax>(
4444
ToCommaSeparatedList(
45-
_parameterGetters.Select(a =>
45+
_constructorParameterGetters.Select(a =>
4646
SyntaxFactory.Argument(GetCreationExpression(a(obj)))))))));
4747

4848
protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression()

src/CSharpScriptSerializer/Extensions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,20 @@ internal static IEnumerable<T> GetFlags<T>(this T flags)
2424

2525
return values;
2626
}
27+
28+
internal static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key)
29+
=> dictionary.GetValueOrDefault(key, default(TValue));
30+
31+
internal static TValue GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary,
32+
TKey key, TValue fallBack)
33+
{
34+
TValue value;
35+
if (dictionary.TryGetValue(key, out value))
36+
{
37+
return value;
38+
}
39+
40+
return fallBack;
41+
}
2742
}
2843
}
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
using Microsoft.CodeAnalysis.CSharp.Syntax;
2-
31
namespace CSharpScriptSerialization
42
{
53
public interface ICSScriptSerializable
64
{
7-
ExpressionSyntax GetCreation();
5+
ICSScriptSerializer GetSerializer();
86
}
97
}

src/CSharpScriptSerializer/LiteralCSScriptSerializer.cs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
3+
using Microsoft.CodeAnalysis;
24
using Microsoft.CodeAnalysis.CSharp;
35
using Microsoft.CodeAnalysis.CSharp.Syntax;
46

@@ -17,6 +19,24 @@ public LiteralCSScriptSerializer(Type type, SyntaxKind kind)
1719
public override ExpressionSyntax GetCreation(object obj)
1820
=> SyntaxFactory.LiteralExpression(
1921
Kind,
20-
SyntaxFactory.Literal((dynamic)obj));
22+
LiteralFactories[obj.GetType()](obj));
23+
24+
private static readonly Dictionary<Type, Func<object, SyntaxToken>> LiteralFactories =
25+
new Dictionary<Type, Func<object, SyntaxToken>>
26+
{
27+
{typeof(char), x => SyntaxFactory.Literal((char)x)},
28+
{typeof(decimal), x => SyntaxFactory.Literal((decimal)x)},
29+
{typeof(double), x => SyntaxFactory.Literal((double)x)},
30+
{typeof(float), x => SyntaxFactory.Literal((float)x)},
31+
{typeof(int), x => SyntaxFactory.Literal((int)x)},
32+
{typeof(long), x => SyntaxFactory.Literal((long)x)},
33+
{typeof(string), x => SyntaxFactory.Literal((string)x)},
34+
{typeof(uint), x => SyntaxFactory.Literal((uint)x)},
35+
{typeof(ulong), x => SyntaxFactory.Literal((ulong)x)},
36+
{typeof(short), x => SyntaxFactory.Literal((short)x)},
37+
{typeof(byte), x => SyntaxFactory.Literal((byte)x)},
38+
{typeof(ushort), x => SyntaxFactory.Literal((ushort)x)},
39+
{typeof(sbyte), x => SyntaxFactory.Literal((sbyte)x)}
40+
};
2141
}
2242
}

src/CSharpScriptSerializer/PropertyCSScriptSerializer.cs

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,36 +23,64 @@ public PropertyCSScriptSerializer(IReadOnlyCollection<Func<T, object>> argumentG
2323
}
2424

2525
public PropertyCSScriptSerializer(IEnumerable<PropertyInfo> properties)
26-
: this(properties, parameterGetters: null)
26+
: this(properties, constructorParameterGetters: null)
2727
{
2828
}
2929

3030
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object>> propertyValueGetters)
31-
: this(propertyValueGetters, parameterGetters: null)
31+
: this(propertyValueGetters, constructorParameterGetters: null)
3232
{
3333
}
3434

3535
public PropertyCSScriptSerializer(IEnumerable<PropertyInfo> properties,
36-
IReadOnlyCollection<Func<T, object>> parameterGetters)
36+
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)
3755
: this(
38-
properties.Select(p => new PropertyData(p.Name, p.PropertyType, CreatePropertyInitializer(p))).ToArray(),
39-
parameterGetters)
56+
propertyValueGetters,
57+
constructorParameterGetters,
58+
propertyDefaults.ToDictionary<KeyValuePair<string, object>, string, Func<T, object>>(
59+
p => p.Key,
60+
p => o => p.Value))
4061
{
4162
}
4263

4364
public PropertyCSScriptSerializer(IReadOnlyDictionary<string, Func<T, object>> propertyValueGetters,
44-
IReadOnlyCollection<Func<T, object>> parameterGetters)
45-
: base(parameterGetters)
65+
IReadOnlyCollection<Func<T, object>> constructorParameterGetters,
66+
IReadOnlyDictionary<string, Func<T, object>> propertyDefaultGetters)
67+
: this(constructorParameterGetters)
4668
{
4769
var properties = typeof(T).GetTypeInfo()
48-
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
49-
.ToDictionary(p => p.Name);
50-
_propertyData = propertyValueGetters.Select(p => new PropertyData(p.Key, properties[p.Key].PropertyType, p.Value)).ToArray();
70+
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
71+
.ToDictionary(p => p.Name);
72+
_propertyData = propertyValueGetters.Select(
73+
p => new PropertyData(
74+
p.Key,
75+
properties[p.Key].PropertyType,
76+
p.Value,
77+
propertyDefaultGetters.GetValueOrDefault(p.Key, o => GetDefault(properties[p.Key].PropertyType))))
78+
.ToArray();
5179
}
5280

5381
protected PropertyCSScriptSerializer(IReadOnlyCollection<PropertyData> propertyData,
54-
IReadOnlyCollection<Func<T, object>> parameterGetters)
55-
: base(parameterGetters)
82+
IReadOnlyCollection<Func<T, object>> constructorParameterGetters)
83+
: base(constructorParameterGetters)
5684
{
5785
_propertyData = propertyData;
5886
}
@@ -62,21 +90,25 @@ protected PropertyCSScriptSerializer(IReadOnlyCollection<PropertyData> propertyD
6290
public override ExpressionSyntax GetCreation(object obj)
6391
=> GetObjectCreationExpression((T)obj);
6492

65-
// TODO: custom defaults
6693
protected override ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
6794
=> base.GetObjectCreationExpression(obj)
6895
.WithInitializer(AddNewLine(
6996
SyntaxFactory.InitializerExpression(
7097
SyntaxKind.ObjectInitializerExpression,
7198
SyntaxFactory.SeparatedList<ExpressionSyntax>(
7299
ToCommaSeparatedList(_propertyData
73-
.Select(p => new {p.PropertyName, p.PropertyType, PropertyValue = p.PropertyInitializer(obj)})
74-
.Where(p => !IsDefault(p.PropertyValue, p.PropertyType))
75-
.Select(p =>
76-
SyntaxFactory.AssignmentExpression(
77-
SyntaxKind.SimpleAssignmentExpression,
78-
SyntaxFactory.IdentifierName(p.PropertyName),
79-
GetCreationExpression(p.PropertyValue))))))));
100+
.Select(p => new
101+
{
102+
p.PropertyName,
103+
p.PropertyType,
104+
PropertyValue = p.PropertyValueGetter(obj),
105+
PropertyDefault = p.PropertyDefaultGetter(obj)
106+
})
107+
.Where(p => !Equals(p.PropertyValue, p.PropertyDefault))
108+
.Select(p => SyntaxFactory.AssignmentExpression(
109+
SyntaxKind.SimpleAssignmentExpression,
110+
SyntaxFactory.IdentifierName(p.PropertyName),
111+
GetCreationExpression(p.PropertyValue))))))));
80112

81113
protected static Func<T, object> CreatePropertyInitializer(PropertyInfo property)
82114
{
@@ -91,16 +123,22 @@ protected static Func<T, object> CreatePropertyInitializer(PropertyInfo property
91123

92124
protected class PropertyData
93125
{
94-
public PropertyData(string propertyName, Type propertyType, Func<T, object> propertyInitializer)
126+
public PropertyData(
127+
string propertyName,
128+
Type propertyType,
129+
Func<T, object> propertyValueGetter,
130+
Func<T, object> propertyDefaultGetter)
95131
{
96132
PropertyName = propertyName;
97133
PropertyType = propertyType;
98-
PropertyInitializer = propertyInitializer;
134+
PropertyValueGetter = propertyValueGetter;
135+
PropertyDefaultGetter = propertyDefaultGetter;
99136
}
100137

101138
public string PropertyName { get; }
102139
public Type PropertyType { get; }
103-
public Func<T, object> PropertyInitializer { get; }
140+
public Func<T, object> PropertyValueGetter { get; }
141+
public Func<T, object> PropertyDefaultGetter { get; }
104142
}
105143
}
106144
}

0 commit comments

Comments
 (0)