Skip to content

Commit b65fe86

Browse files
supermihimatt-lethargic
authored andcommitted
Improve code quality (#88)
* replace GeoJsonObject.Type by abstract read-only property The Type now resolves to a constant enum value for each subclass. Benefits: - allows to remove setter -> objects are more immutable now - reduces memory footprint of each object by one string - impossible to accidentally forget to set the Type in a subclass constructor * make Point.Coordinates readonly & remove parameterless constructor * Increase immutability of Polygon and LineString & avoid explicit List types Both classes' coordinates field is read-only now and of IReadOnlyList<T> type instead of List<T>, which prevents manipulation after creation. For this to work, additional constructors were introduced that take nested double enumerables as in the GeoJSON spec. * Rename Converters & extend previous work to more classes The previous converter names were highly misleading because e.g. PolygonConverter did NOT read/write Polygon object but instead only the Coordinates property of a Polygon. * Make MultiPoint & MultiPolygon immutable and improve corresponding converters * Make Position formally immutable (and smaller in memory) * Various small code style and documentation improvements * Let Feature<TGeometry> derive from Feature<TGeometry, TProps> Avoids duplication of code. * Streamline the style of JSON converters * Remove unused (and, from its XML doc, probably very old) ParsingException class * Position.cs: remove redundant null checks & remove misleading comment * Add missing and fix existing XML docs. * Fix for net35 target: replace IReadOnlyList by ReadOnlyCollection
1 parent 9d579d6 commit b65fe86

25 files changed

+338
-554
lines changed

src/GeoJSON.Net.Tests/Geometry/LineStringTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ public void Constructor_No_Coordinates_Throws_Exception()
9393
[Test]
9494
public void Constructor_Null_Coordinates_Throws_Exception()
9595
{
96-
Assert.Throws<ArgumentNullException>(() => new LineString(null));
96+
Assert.Throws<ArgumentNullException>(() => new LineString((IEnumerable<IPosition>)null));
9797
}
9898

9999
private LineString GetLineString(double offset = 0.0)

src/GeoJSON.Net/Converters/CrsConverter.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
// Copyright © Joerg Battermann 2014, Matt Hunt 2017
22

33
using System;
4-
#if (!NET35 || !NET40)
5-
using System.Reflection;
6-
#endif
74
using GeoJSON.Net.CoordinateReferenceSystem;
85
using Newtonsoft.Json;
96
using Newtonsoft.Json.Linq;
@@ -24,11 +21,7 @@ public class CrsConverter : JsonConverter
2421
/// </returns>
2522
public override bool CanConvert(Type objectType)
2623
{
27-
#if (NET35 || NET40)
28-
return typeof(ICRSObject).IsAssignableFrom(objectType);
29-
#else
30-
return typeof(ICRSObject).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
31-
#endif
24+
return typeof(ICRSObject).IsAssignableFromType(objectType);
3225
}
3326

3427
/// <summary>

src/GeoJSON.Net/Converters/GeoJsonConverter.cs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq;
6-
#if (!NET35 || !NET40)
7-
using System.Reflection;
8-
#endif
96
using GeoJSON.Net.Feature;
107
using GeoJSON.Net.Geometry;
118
using Newtonsoft.Json;
@@ -27,11 +24,7 @@ public class GeoJsonConverter : JsonConverter
2724
/// </returns>
2825
public override bool CanConvert(Type objectType)
2926
{
30-
#if (NET35 || NET40)
31-
return typeof(IGeoJSONObject).IsAssignableFrom(objectType);
32-
#else
33-
return typeof(IGeoJSONObject).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
34-
#endif
27+
return typeof(IGeoJSONObject).IsAssignableFromType(objectType);
3528
}
3629

3730
/// <summary>

src/GeoJSON.Net/Converters/GeometryConverter.cs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,8 @@
22

33
using System;
44
using System.Collections.Generic;
5+
using System.Collections.ObjectModel;
56
using System.Linq;
6-
#if (!NET35 || !NET40)
7-
using System.Reflection;
8-
#endif
97
using GeoJSON.Net.Geometry;
108
using Newtonsoft.Json;
119
using Newtonsoft.Json.Linq;
@@ -26,11 +24,7 @@ public class GeometryConverter : JsonConverter
2624
/// </returns>
2725
public override bool CanConvert(Type objectType)
2826
{
29-
#if (NET35 || NET40)
30-
return typeof(IGeometryObject).IsAssignableFrom(objectType);
31-
#else
32-
return typeof(IGeometryObject).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo());
33-
#endif
27+
return typeof(IGeometryObject).IsAssignableFromType(objectType);
3428
}
3529

3630
/// <summary>
@@ -54,8 +48,8 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
5448
return ReadGeoJson(value);
5549
case JsonToken.StartArray:
5650
var values = JArray.Load(reader);
57-
var geometries = new List<IGeometryObject>(values.Count);
58-
geometries.AddRange(values.Cast<JObject>().Select(ReadGeoJson));
51+
var geometries = new ReadOnlyCollection<IGeometryObject>(
52+
values.Cast<JObject>().Select(ReadGeoJson).ToArray());
5953
return geometries;
6054
}
6155

src/GeoJSON.Net/Converters/PolygonConverter.cs renamed to src/GeoJSON.Net/Converters/LineStringEnumerableConverter.cs

Lines changed: 19 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,19 @@
22

33
using System;
44
using System.Collections.Generic;
5+
using System.Linq;
56
using GeoJSON.Net.Geometry;
67
using Newtonsoft.Json;
8+
using Newtonsoft.Json.Linq;
79

810
namespace GeoJSON.Net.Converters
911
{
1012
/// <summary>
11-
/// Converter to read and write the <see cref="Polygon" /> type.
13+
/// Converter to read and write the <see cref="IEnumerable{LineString}" /> type.
1214
/// </summary>
13-
public class PolygonConverter : JsonConverter
15+
public class LineStringEnumerableConverter : JsonConverter
1416
{
15-
private static readonly LineStringConverter LineStringConverter = new LineStringConverter();
17+
private static readonly PositionEnumerableConverter LineStringConverter = new PositionEnumerableConverter();
1618

1719
/// <summary>
1820
/// Determines whether this instance can convert the specified object type.
@@ -23,7 +25,7 @@ public class PolygonConverter : JsonConverter
2325
/// </returns>
2426
public override bool CanConvert(Type objectType)
2527
{
26-
return objectType == typeof(Polygon);
28+
return typeof(IEnumerable<LineString>).IsAssignableFromType(objectType);
2729
}
2830

2931
/// <summary>
@@ -38,16 +40,13 @@ public override bool CanConvert(Type objectType)
3840
/// </returns>
3941
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
4042
{
41-
var rings = serializer.Deserialize<double[][][]>(reader);
42-
var lineStrings = new List<LineString>(rings.Length);
43-
44-
foreach (var ring in rings)
45-
{
46-
var positions = (IEnumerable<IPosition>)LineStringConverter.ReadJson(reader, typeof(LineString), ring, serializer);
47-
lineStrings.Add(new LineString(positions));
48-
}
49-
50-
return lineStrings;
43+
var rings = existingValue as JArray ?? serializer.Deserialize<JArray>(reader);
44+
return rings.Select(ring => new LineString((IEnumerable<IPosition>) LineStringConverter.ReadJson(
45+
reader,
46+
typeof(IEnumerable<IPosition>),
47+
ring,
48+
serializer)))
49+
.ToArray();
5150
}
5251

5352
/// <summary>
@@ -58,28 +57,18 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist
5857
/// <param name="serializer">The calling serializer.</param>
5958
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
6059
{
61-
var coordinateElements = value as List<LineString>;
62-
if (coordinateElements != null && coordinateElements.Count > 0)
60+
if (value is IEnumerable<LineString> coordinateElements)
6361
{
64-
if (coordinateElements[0].Coordinates[0] is Position)
65-
{
66-
writer.WriteStartArray();
67-
68-
foreach (var subPolygon in coordinateElements)
69-
{
70-
LineStringConverter.WriteJson(writer, subPolygon.Coordinates, serializer);
71-
}
72-
73-
writer.WriteEndArray();
74-
}
75-
else
62+
writer.WriteStartArray();
63+
foreach (var subPolygon in coordinateElements)
7664
{
77-
throw new NotImplementedException();
65+
LineStringConverter.WriteJson(writer, subPolygon.Coordinates, serializer);
7866
}
67+
writer.WriteEndArray();
7968
}
8069
else
8170
{
82-
serializer.Serialize(writer, value);
71+
throw new ArgumentException($"{nameof(LineStringEnumerableConverter)}: unsupported value type");
8372
}
8473
}
8574
}

src/GeoJSON.Net/Converters/MultiPointConverter.cs

Lines changed: 0 additions & 71 deletions
This file was deleted.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright � Joerg Battermann 2014, Matt Hunt 2017
2+
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using GeoJSON.Net.Geometry;
7+
using Newtonsoft.Json;
8+
using Newtonsoft.Json.Linq;
9+
10+
namespace GeoJSON.Net.Converters
11+
{
12+
/// <summary>
13+
/// Converter to read and write the <see cref="IEnumerable{Point}" /> type.
14+
/// </summary>
15+
public class PointEnumerableConverter : JsonConverter
16+
{
17+
private static readonly PositionConverter PositionConverter = new PositionConverter();
18+
/// <inheritdoc />
19+
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
20+
{
21+
if (value is IEnumerable<Point> points)
22+
{
23+
writer.WriteStartArray();
24+
foreach (var point in points)
25+
{
26+
PositionConverter.WriteJson(writer, point.Coordinates, serializer);
27+
}
28+
writer.WriteEndArray();
29+
}
30+
else
31+
{
32+
throw new ArgumentException($"{nameof(PointEnumerableConverter)}: unsupported value {value}");
33+
}
34+
}
35+
36+
/// <inheritdoc />
37+
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
38+
{
39+
var coordinates = existingValue as JArray ?? serializer.Deserialize<JArray>(reader);
40+
return coordinates.Select(position => new Point(position.ToObject<IEnumerable<double>>().ToPosition()));
41+
}
42+
43+
/// <inheritdoc />
44+
public override bool CanConvert(Type objectType)
45+
{
46+
return objectType == typeof(IEnumerable<Point>);
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)