From 3ddc59c3863d311bf6e9bed95f880c48ebf4ee35 Mon Sep 17 00:00:00 2001 From: RogueException Date: Tue, 27 Dec 2016 14:52:22 -0400 Subject: [PATCH] Added NullableConverter, fixed Image serialization --- .../Net/Converters/DiscordContractResolver.cs | 69 ++++++++----------- .../Net/Converters/NullableConverter.cs | 50 ++++++++++++++ .../Net/Converters/NullableUInt64Converter.cs | 32 --------- 3 files changed, 77 insertions(+), 74 deletions(-) create mode 100644 src/Discord.Net.Core/Net/Converters/NullableConverter.cs delete mode 100644 src/Discord.Net.Core/Net/Converters/NullableUInt64Converter.cs diff --git a/src/Discord.Net.Core/Net/Converters/DiscordContractResolver.cs b/src/Discord.Net.Core/Net/Converters/DiscordContractResolver.cs index 3357932d4..104b913da 100644 --- a/src/Discord.Net.Core/Net/Converters/DiscordContractResolver.cs +++ b/src/Discord.Net.Core/Net/Converters/DiscordContractResolver.cs @@ -22,26 +22,7 @@ namespace Discord.Net.Converters var propInfo = member as PropertyInfo; if (propInfo != null) { - JsonConverter converter; - Type type = propInfo.PropertyType; - Type genericType = type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : null; - - if (genericType == typeof(Optional<>)) - { - var typeInput = propInfo.DeclaringType; - var innerTypeOutput = type.GenericTypeArguments[0]; - - var getter = typeof(Func<,>).MakeGenericType(typeInput, type); - var getterDelegate = propInfo.GetMethod.CreateDelegate(getter); - var shouldSerialize = _shouldSerialize.MakeGenericMethod(typeInput, innerTypeOutput); - var shouldSerializeDelegate = (Func)shouldSerialize.CreateDelegate(typeof(Func)); - property.ShouldSerialize = x => shouldSerializeDelegate(x, getterDelegate); - - converter = MakeGenericConverter(propInfo, typeof(OptionalConverter<>), innerTypeOutput); - } - else - converter = GetConverter(propInfo, type); - + var converter = GetConverter(property, propInfo, propInfo.PropertyType, 0); if (converter != null) { property.Converter = converter; @@ -53,26 +34,38 @@ namespace Discord.Net.Converters return property; } - private static JsonConverter GetConverter(PropertyInfo propInfo, Type type, TypeInfo typeInfo = null, int depth = 0) + private static JsonConverter GetConverter(JsonProperty property, PropertyInfo propInfo, Type type, int depth) { if (type.IsArray) - return MakeGenericConverter(propInfo, typeof(ArrayConverter<>), type.GetElementType()); + return MakeGenericConverter(property, propInfo, typeof(ArrayConverter<>), type.GetElementType(), depth); if (type.IsConstructedGenericType) { Type genericType = type.GetGenericTypeDefinition(); - if (genericType == typeof(EntityOrId<>)) - return MakeGenericConverter(propInfo, typeof(UInt64EntityOrIdConverter<>), type.GenericTypeArguments[0]); - } + if (depth == 0 && genericType == typeof(Optional<>)) + { + var typeInput = propInfo.DeclaringType; + var innerTypeOutput = type.GenericTypeArguments[0]; - bool hasInt53 = propInfo.GetCustomAttribute() != null; + var getter = typeof(Func<,>).MakeGenericType(typeInput, type); + var getterDelegate = propInfo.GetMethod.CreateDelegate(getter); + var shouldSerialize = _shouldSerialize.MakeGenericMethod(typeInput, innerTypeOutput); + var shouldSerializeDelegate = (Func)shouldSerialize.CreateDelegate(typeof(Func)); + property.ShouldSerialize = x => shouldSerializeDelegate(x, getterDelegate); + + return MakeGenericConverter(property, propInfo, typeof(OptionalConverter<>), innerTypeOutput, depth); + } + else if (genericType == typeof(Nullable<>)) + return MakeGenericConverter(property, propInfo, typeof(NullableConverter<>), type.GenericTypeArguments[0], depth); + else if (genericType == typeof(EntityOrId<>)) + return MakeGenericConverter(property, propInfo, typeof(UInt64EntityOrIdConverter<>), type.GenericTypeArguments[0], depth); + } //Primitives + bool hasInt53 = propInfo.GetCustomAttribute() != null; if (!hasInt53) { if (type == typeof(ulong)) return UInt64Converter.Instance; - if (type == typeof(ulong?)) - return NullableUInt64Converter.Instance; } //Enums @@ -82,12 +75,11 @@ namespace Discord.Net.Converters return UserStatusConverter.Instance; //Special - if (type == typeof(Image)) - return ImageConverter.Instance; - - if (typeInfo == null) typeInfo = type.GetTypeInfo(); + if (type == typeof(API.Image)) + return ImageConverter.Instance; //Entities + var typeInfo = type.GetTypeInfo(); if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity))) return UInt64EntityConverter.Instance; if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity))) @@ -101,18 +93,11 @@ namespace Discord.Net.Converters return (getter as Func>)((TOwner)owner).IsSpecified; } - private static JsonConverter MakeGenericConverter(PropertyInfo propInfo, Type converterType, Type innerType) + private static JsonConverter MakeGenericConverter(JsonProperty property, PropertyInfo propInfo, Type converterType, Type innerType, int depth) { var genericType = converterType.MakeGenericType(innerType).GetTypeInfo(); - //var instanceField = genericType.GetDeclaredField("Instance"); - //var converter = instanceField.GetValue(null) as JsonConverter; - //if (converter == null) - //{ - var innerConverter = GetConverter(propInfo, innerType); - var converter = genericType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter; - //instanceField.SetValue(null, converter); - //} - return converter; + var innerConverter = GetConverter(property, propInfo, innerType, depth + 1); + return genericType.DeclaredConstructors.First().Invoke(new object[] { innerConverter }) as JsonConverter; } } } diff --git a/src/Discord.Net.Core/Net/Converters/NullableConverter.cs b/src/Discord.Net.Core/Net/Converters/NullableConverter.cs new file mode 100644 index 000000000..0b149e725 --- /dev/null +++ b/src/Discord.Net.Core/Net/Converters/NullableConverter.cs @@ -0,0 +1,50 @@ +using Newtonsoft.Json; +using System; + +namespace Discord.Net.Converters +{ + internal class NullableConverter : JsonConverter + where T : struct + { + private readonly JsonConverter _innerConverter; + + public override bool CanConvert(Type objectType) => true; + public override bool CanRead => true; + public override bool CanWrite => true; + + public NullableConverter(JsonConverter innerConverter) + { + _innerConverter = innerConverter; + } + + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + object value = reader.Value; + if (value == null) + return null; + else + { + T obj; + if (_innerConverter != null) + obj = (T)_innerConverter.ReadJson(reader, typeof(T), null, serializer); + else + obj = serializer.Deserialize(reader); + return obj; + } + } + + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (value == null) + writer.WriteNull(); + else + { + var nullable = (T?)value; + if (_innerConverter != null) + _innerConverter.WriteJson(writer, nullable.Value, serializer); + else + serializer.Serialize(writer, nullable.Value, typeof(T)); + } + } + } +} diff --git a/src/Discord.Net.Core/Net/Converters/NullableUInt64Converter.cs b/src/Discord.Net.Core/Net/Converters/NullableUInt64Converter.cs deleted file mode 100644 index fa22da656..000000000 --- a/src/Discord.Net.Core/Net/Converters/NullableUInt64Converter.cs +++ /dev/null @@ -1,32 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Globalization; - -namespace Discord.Net.Converters -{ - internal class NullableUInt64Converter : JsonConverter - { - public static readonly NullableUInt64Converter Instance = new NullableUInt64Converter(); - - public override bool CanConvert(Type objectType) => true; - public override bool CanRead => true; - public override bool CanWrite => true; - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - object value = reader.Value; - if (value != null) - return ulong.Parse(value.ToString(), NumberStyles.None, CultureInfo.InvariantCulture); - else - return null; - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - if (value != null) - writer.WriteValue(((ulong?)value).Value.ToString(CultureInfo.InvariantCulture)); - else - writer.WriteNull(); - } - } -}