-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathHashSetOfNumberConverter.cs
87 lines (78 loc) · 3.8 KB
/
HashSetOfNumberConverter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
namespace NServiceBus.Persistence.DynamoDB
{
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
sealed class HashSetOfNumberConverter : JsonConverterFactory
{
// This is a cryptic property name to make sure we never class with the user data
const string PropertyName = "HashSetNumberContent838D2F22-0D5B-4831-8C04-17C7A6329B31";
public override bool CanConvert(Type typeToConvert)
{
if (!typeToConvert.IsGenericType)
{
return false;
}
var innerTypeToConvert = typeToConvert.GetGenericArguments()[0];
var isNumberTypeSupported = innerTypeToConvert == typeof(byte) ||
innerTypeToConvert == typeof(sbyte) ||
innerTypeToConvert == typeof(ushort) ||
innerTypeToConvert == typeof(uint) ||
innerTypeToConvert == typeof(ulong) ||
innerTypeToConvert == typeof(long) ||
innerTypeToConvert == typeof(short) ||
innerTypeToConvert == typeof(int) ||
innerTypeToConvert == typeof(double) ||
innerTypeToConvert == typeof(decimal) ||
innerTypeToConvert == typeof(float);
return isNumberTypeSupported &&
// This check is fairly expensive so we do it only once we know it is a number type that is supported
typeToConvert.IsAssignableToGenericType(typeof(ISet<>));
}
public override JsonConverter CreateConverter(Type type, JsonSerializerOptions options)
{
Type valueType = type.GetGenericArguments()[0];
var converter = (JsonConverter)Activator.CreateInstance(
typeof(SetConverter<,>)
.MakeGenericType(new Type[] { type, valueType }),
BindingFlags.Instance | BindingFlags.Public,
binder: null,
args: null,
culture: null)!;
return converter;
}
sealed class SetConverter<TSet, TValue> : JsonConverter<TSet>
where TSet : ISet<TValue>
where TValue : struct
{
public override TSet? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
throw new NotImplementedException(
$"The {GetType().FullName} should never be used on the read path since its sole purpose is to preserve information on the write path");
public override void Write(Utf8JsonWriter writer, TSet value, JsonSerializerOptions options)
{
writer.WriteStartObject();
writer.WritePropertyName(PropertyName);
// Deliberately not passing the options to use the default json serialization behavior
JsonSerializer.Serialize(writer, value);
writer.WriteEndObject();
}
}
public static bool TryExtract(JsonProperty property, out List<string?>? numbersAsStrings)
{
numbersAsStrings = null;
if (!property.NameEquals(PropertyName))
{
return false;
}
foreach (var innerElement in property.Value.EnumerateArray())
{
numbersAsStrings ??= new List<string?>(property.Value.GetArrayLength());
numbersAsStrings.Add(innerElement.ToString());
}
numbersAsStrings ??= new List<string?>(0);
return true;
}
}
}