Skip to content

Commit f9d834b

Browse files
committed
Simplify empty collections
1 parent 9d052bf commit f9d834b

File tree

8 files changed

+104
-51
lines changed

8 files changed

+104
-51
lines changed

src/CSharpScriptSerializer/ArrayCSScriptSerializer.cs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
using System;
2+
using System.Collections.Generic;
23
using System.Collections.Immutable;
34
using System.Linq;
45
using Microsoft.CodeAnalysis.CSharp;
56
using Microsoft.CodeAnalysis.CSharp.Syntax;
7+
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
68

79
namespace CSharpScriptSerialization
810
{
@@ -14,15 +16,31 @@ public ArrayCSScriptSerializer(Type type)
1416
}
1517

1618
public override ExpressionSyntax GetCreation(object obj)
17-
=> SyntaxFactory.ArrayCreationExpression((ArrayTypeSyntax)GetTypeSyntax(Type))
18-
.WithInitializer(AddNewLine(
19-
GetArrayInitializerExpression((Array)obj, startingDimension: 0, indices: ImmutableArray<int>.Empty)));
19+
{
20+
var array = (Array)obj;
21+
return array.Length == 0
22+
? ArrayCreationExpression(ArrayType(GetTypeSyntax(GetArrayElementType(Type)),
23+
List(GetEmptyArrayRanks(Type))))
24+
: ArrayCreationExpression((ArrayTypeSyntax)GetTypeSyntax(Type)).WithInitializer(AddNewLine(
25+
GetArrayInitializerExpression(array, startingDimension: 0, indices: ImmutableArray<int>.Empty)));
26+
}
27+
28+
private static IEnumerable<ArrayRankSpecifierSyntax> GetEmptyArrayRanks(Type type)
29+
=> new[]
30+
{
31+
ArrayRankSpecifier(
32+
SeparatedList<ExpressionSyntax>(
33+
ToCommaSeparatedList(
34+
Enumerable.Repeat(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(0)),
35+
type.GetArrayRank()))))
36+
}
37+
.Concat(GetArrayRanks(type.GetElementType()));
2038

2139
private InitializerExpressionSyntax GetArrayInitializerExpression
2240
(Array array, int startingDimension, ImmutableArray<int> indices)
23-
=> SyntaxFactory.InitializerExpression(
41+
=> InitializerExpression(
2442
SyntaxKind.ArrayInitializerExpression,
25-
SyntaxFactory.SeparatedList<ExpressionSyntax>(
43+
SeparatedList<ExpressionSyntax>(
2644
ToCommaSeparatedList(Enumerable.Range(
2745
array.GetLowerBound(startingDimension),
2846
array.GetUpperBound(startingDimension) - array.GetLowerBound(startingDimension) + 1)

src/CSharpScriptSerializer/CSScriptSerializer.cs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -527,17 +527,19 @@ private static NameSyntax GetNameSyntax(Type type, List<Type> genericArguments)
527527
return QualifiedName(GetNameSyntax(declaringType, declaringTypeGenericArguments), simpleName);
528528
}
529529

530-
private static Type GetArrayElementType(Type type)
530+
protected static Type GetArrayElementType(Type type)
531531
=> type.IsArray ? GetArrayElementType(type.GetElementType()) : type;
532532

533-
private static IEnumerable<ArrayRankSpecifierSyntax> GetArrayRanks(Type type)
533+
protected static IEnumerable<ArrayRankSpecifierSyntax> GetArrayRanks(Type type)
534534
=> type == null || !type.IsArray
535535
? Enumerable.Empty<ArrayRankSpecifierSyntax>()
536-
: Enumerable.Repeat(ArrayRankSpecifier(
537-
SeparatedList<ExpressionSyntax>(
538-
ToCommaSeparatedList(
539-
Enumerable.Repeat(OmittedArraySizeExpression(), type.GetArrayRank())))),
540-
count: 1)
536+
: new[]
537+
{
538+
ArrayRankSpecifier(
539+
SeparatedList<ExpressionSyntax>(
540+
ToCommaSeparatedList(
541+
Enumerable.Repeat(OmittedArraySizeExpression(), type.GetArrayRank()))))
542+
}
541543
.Concat(GetArrayRanks(type.GetElementType()));
542544

543545
protected static TSyntax AddNewLine<TSyntax>(TSyntax expression)

src/CSharpScriptSerializer/CSharpScriptSerializer.csproj

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<PackageId>CSharpScriptSerializer</PackageId>
66
<AssemblyTitle>CSharpScriptSerializer</AssemblyTitle>
77
<Title>CSharpScriptSerializer</Title>
8-
<VersionPrefix>3.0.2</VersionPrefix>
8+
<VersionPrefix>3.0.3</VersionPrefix>
99
<TargetFrameworks>netstandard2.1</TargetFrameworks>
1010
<NetStandardImplicitPackageVersion>2.0.3</NetStandardImplicitPackageVersion>
1111
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
@@ -15,6 +15,8 @@
1515
<PackageTags>Roslyn;CSharp;C#;CSX;Script;Serialization</PackageTags>
1616
<PackageReleaseNotes>
1717
<![CDATA[
18+
Version 3.0.3
19+
* Simplify empty collections
1820
Version 3.0.2
1921
* Remove trailing new line
2022
Version 3.0.0
@@ -29,10 +31,6 @@ Version 1.5.0
2931
* Update to Roslyn V2.8.0
3032
Version 1.4.0
3133
* Add support for ValueTuple, Type and plain Object
32-
Version 1.3.0
33-
* Update to Roslyn V2.3.1
34-
Version 1.2.0
35-
* Update to Roslyn V2
3634
]]>
3735
</PackageReleaseNotes>
3836
<PackageProjectUrl>https://github.com/AndriySvyryd/CSharpScriptSerializer</PackageProjectUrl>

src/CSharpScriptSerializer/CollectionCSScriptSerializer.cs

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,19 @@ public CollectionCSScriptSerializer(
8787
public override ExpressionSyntax GetCreation(object obj) => GetObjectCreationExpression((T)obj);
8888

8989
protected override ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
90-
=> base.GetObjectCreationExpression(obj)
91-
.WithInitializer(AddNewLine(
92-
SyntaxFactory.InitializerExpression(
93-
SyntaxKind.CollectionInitializerExpression,
94-
SyntaxFactory.SeparatedList<ExpressionSyntax>(
95-
ToCommaSeparatedList(_getEnumerable(obj)
96-
.Select(GetElementExpression))))));
90+
{
91+
var list = _getEnumerable(obj).ToList();
92+
return list.Count == 0
93+
? base.GetObjectCreationExpression(obj)
94+
.WithArgumentList(SyntaxFactory.ArgumentList())
95+
: base.GetObjectCreationExpression(obj)
96+
.WithInitializer(AddNewLine(
97+
SyntaxFactory.InitializerExpression(
98+
SyntaxKind.CollectionInitializerExpression,
99+
SyntaxFactory.SeparatedList<ExpressionSyntax>(
100+
ToCommaSeparatedList(list
101+
.Select(GetElementExpression))))));
102+
}
97103

98104
protected virtual ExpressionSyntax GetElementExpression(object element)
99105
=> _elementDecomposers == null

src/CSharpScriptSerializer/ConstructorCSScriptSerializer.cs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@ public ConstructorCSScriptSerializer(IReadOnlyCollection<Func<T, object>> constr
3030
public override ExpressionSyntax GetCreation(object obj) => GetObjectCreationExpression((T)obj);
3131

3232
protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
33+
=> GetObjectCreationExpression(obj, GenerateEmptyArgumentList);
34+
35+
protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj, bool generateEmptyArgumentList)
3336
=> _constructorParameterGetters == null
3437
|| _constructorParameterGetters.Count == 0
35-
? GenerateEmptyArgumentList
38+
? generateEmptyArgumentList
3639
? GetObjectCreationExpression().WithArgumentList(SyntaxFactory.ArgumentList())
3740
: GetObjectCreationExpression()
3841
: GetObjectCreationExpression()
@@ -43,7 +46,6 @@ protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression(T o
4346
SyntaxFactory.Argument(GetCreationExpression(a(obj)))))))));
4447

4548
protected virtual ObjectCreationExpressionSyntax GetObjectCreationExpression()
46-
=> _objectCreationExpression ??
47-
(_objectCreationExpression = SyntaxFactory.ObjectCreationExpression(GetTypeSyntax(Type)));
49+
=>_objectCreationExpression ??= SyntaxFactory.ObjectCreationExpression(GetTypeSyntax(Type));
4850
}
4951
}

src/CSharpScriptSerializer/PropertyCSScriptSerializer.cs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -181,17 +181,23 @@ public override ExpressionSyntax GetCreation(object obj)
181181
}
182182

183183
protected override ObjectCreationExpressionSyntax GetObjectCreationExpression(T obj)
184-
=> base.GetObjectCreationExpression(obj)
185-
.WithInitializer(AddNewLine(
186-
InitializerExpression(
187-
SyntaxKind.ObjectInitializerExpression,
188-
SeparatedList<ExpressionSyntax>(
189-
ToCommaSeparatedList(_propertyData
190-
.Where(p => p.PropertyCondition(obj, p.PropertyValueGetter(obj)))
191-
.Select(p => AssignmentExpression(
192-
SyntaxKind.SimpleAssignmentExpression,
193-
IdentifierName(p.PropertyName),
194-
GetCreationExpression(p.PropertyValueGetter(obj)))))))));
184+
{
185+
var properties = _propertyData
186+
.Where(p => p.PropertyCondition(obj, p.PropertyValueGetter(obj)))
187+
.Select(p => AssignmentExpression(
188+
SyntaxKind.SimpleAssignmentExpression,
189+
IdentifierName(p.PropertyName),
190+
GetCreationExpression(p.PropertyValueGetter(obj)))).ToList();
191+
192+
var expression = base.GetObjectCreationExpression(obj, generateEmptyArgumentList: properties.Count == 0)
193+
.WithInitializer(AddNewLine(
194+
InitializerExpression(
195+
SyntaxKind.ObjectInitializerExpression,
196+
SeparatedList<ExpressionSyntax>(
197+
ToCommaSeparatedList(properties)))));
198+
199+
return expression;
200+
}
195201

196202
protected static Func<T, object> CreatePropertyValueGetter(PropertyInfo property)
197203
{

test/CSharpScriptSerializer.Tests/NegativeScenarioTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace CSharpScriptSerialization.Tests
77
public class NegativeScenarioTest
88
{
99
[Fact]
10-
public void NousableProperties()
10+
public void NoUsableProperties()
1111
{
1212
var input = new Private();
1313

test/CSharpScriptSerializer.Tests/RoundTrippingTest.cs

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -169,17 +169,13 @@ public void CombinedFlagsEnum()
169169
+ typeof(RoundtrippingTest).Name + "." + typeof(FlagsEnum).Name + "." + FlagsEnum.SecondAndThird, script);
170170
}
171171

172-
[Fact]
173-
public void VerbatimStrings()
174-
{
175-
ValidateStringLiteral("\r", verbatim: true);
176-
ValidateStringLiteral("\n", verbatim: true);
177-
ValidateStringLiteral("\"", verbatim: false);
178-
ValidateStringLiteral("@", verbatim: false);
179-
ValidateStringLiteral("A", verbatim: false);
180-
}
181-
182-
private void ValidateStringLiteral(string input, bool verbatim)
172+
[Theory]
173+
[InlineData("\r", true)]
174+
[InlineData("\n", true)]
175+
[InlineData("\"", false)]
176+
[InlineData("@", false)]
177+
[InlineData("A", false)]
178+
public void VerbatimStrings(string input, bool verbatim)
183179
{
184180
var script = CSScriptSerializer.Serialize(input);
185181
Assert.Equal(verbatim ? '@' : '"', script[0]);
@@ -188,6 +184,16 @@ private void ValidateStringLiteral(string input, bool verbatim)
188184
Assert.Equal(input, output);
189185
}
190186

187+
[Fact]
188+
public void EmptyCollections()
189+
{
190+
Validate(new int?[,] { });
191+
Validate(new List<string[]>[] { });
192+
Validate(new object[][] { });
193+
Validate(new List<string>());
194+
Validate(new Dictionary<bool, bool?>());
195+
}
196+
191197
[Fact]
192198
public void LongString()
193199
{
@@ -211,8 +217,15 @@ public void LongString()
211217
17
212218
18
213219
19";
220+
221+
Validate(input);
222+
}
223+
224+
private static void Validate<T>(T input)
225+
{
214226
var script = CSScriptSerializer.Serialize(input);
215-
var output = CSScriptSerializer.Deserialize<string>(script);
227+
var output = CSScriptSerializer.Deserialize<T>(script);
228+
216229
Assert.Equal(input, output);
217230
}
218231

@@ -349,6 +362,14 @@ public void OverridenProperties()
349362

350363
Assert.Equal(input.Property, output.Property);
351364
Assert.Equal(input.GetSetCount(), output.GetSetCount());
365+
366+
input = new OverrideDerived();
367+
368+
script = CSScriptSerializer.Serialize(input);
369+
output = CSScriptSerializer.Deserialize<OverrideDerived>(script);
370+
371+
Assert.Equal(input.Property, output.Property);
372+
Assert.Equal(input.GetSetCount(), output.GetSetCount());
352373
}
353374

354375
public class OverrideDerived : HiddenBase

0 commit comments

Comments
 (0)