diff --git a/src/Discord.Net/Net/Converters/DiscordContractResolver.cs b/src/Discord.Net/Net/Converters/DiscordContractResolver.cs index be22c9b20..4e3aba41e 100644 --- a/src/Discord.Net/Net/Converters/DiscordContractResolver.cs +++ b/src/Discord.Net/Net/Converters/DiscordContractResolver.cs @@ -3,6 +3,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Reflection; @@ -17,59 +18,34 @@ namespace Discord.Net.Converters { var property = base.CreateProperty(member, memberSerialization); var propInfo = member as PropertyInfo; - if (propInfo != null) { - JsonConverter converter = null; - var type = property.PropertyType; - var typeInfo = type.GetTypeInfo(); + JsonConverter converter; + var type = propInfo.PropertyType; - //Primitives - if (propInfo.GetCustomAttribute() == null) + if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Optional<>)) { - if (type == typeof(ulong)) - converter = UInt64Converter.Instance; - else if (type == typeof(ulong?)) - converter = NullableUInt64Converter.Instance; - else if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEnumerable))) - converter = UInt64ArrayConverter.Instance; - } - if (converter == null) - { - //Enums - if (type == typeof(ChannelType)) - converter = ChannelTypeConverter.Instance; - else if (type == typeof(PermissionTarget)) - converter = PermissionTargetConverter.Instance; - else if (type == typeof(UserStatus)) - converter = UserStatusConverter.Instance; - else if (type == typeof(Direction)) - converter = DirectionConverter.Instance; + var typeInput = propInfo.DeclaringType; + var innerTypeOutput = type.GenericTypeArguments[0]; - //Entities - if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity))) - converter = UInt64EntityConverter.Instance; - else if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity))) - converter = StringEntityConverter.Instance; + 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); - //Special - else if (type == typeof(string) && propInfo.GetCustomAttribute() != null) - converter = ImageConverter.Instance; - else if (type.IsConstructedGenericType && type.GetGenericTypeDefinition() == typeof(Optional<>)) + var converterType = typeof(OptionalConverter<>).MakeGenericType(innerTypeOutput).GetTypeInfo(); + var instanceField = converterType.GetDeclaredField("Instance"); + converter = instanceField.GetValue(null) as JsonConverter; + if (converter == null) { - 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); - - var converterType = typeof(OptionalConverter<>).MakeGenericType(innerTypeOutput); - converter = converterType.GetTypeInfo().GetDeclaredField("Instance").GetValue(null) as JsonConverter; + var innerConverter = GetConverter(propInfo, innerTypeOutput); + converter = converterType.DeclaredConstructors.FirstOrDefault().Invoke(new object[] { innerConverter }) as JsonConverter; + instanceField.SetValue(null, converter); } } + else + converter = GetConverter(propInfo, type); if (converter != null) { @@ -77,10 +53,52 @@ namespace Discord.Net.Converters property.MemberConverter = converter; } } - return property; } + private JsonConverter GetConverter(PropertyInfo propInfo, Type type, TypeInfo typeInfo = null) + { + bool hasInt53 = propInfo.GetCustomAttribute() != null; + + //Primitives + if (!hasInt53) + { + if (type == typeof(ulong)) + return UInt64Converter.Instance; + if (type == typeof(ulong?)) + return NullableUInt64Converter.Instance; + } + + //Enums + if (type == typeof(ChannelType)) + return ChannelTypeConverter.Instance; + if (type == typeof(PermissionTarget)) + return PermissionTargetConverter.Instance; + if (type == typeof(UserStatus)) + return UserStatusConverter.Instance; + if (type == typeof(Direction)) + return DirectionConverter.Instance; + + //Special + if (type == typeof(Stream) && propInfo.GetCustomAttribute() != null) + return ImageConverter.Instance; + + + if (typeInfo == null) typeInfo = type.GetTypeInfo(); + + //Primitives + if (!hasInt53 && typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEnumerable))) + return UInt64ArrayConverter.Instance; + + //Entities + if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity))) + return UInt64EntityConverter.Instance; + if (typeInfo.ImplementedInterfaces.Any(x => x == typeof(IEntity))) + return StringEntityConverter.Instance; + + return null; + } + private static bool ShouldSerialize(object owner, Delegate getter) { return (getter as Func>)((TOwner)owner).IsSpecified; diff --git a/src/Discord.Net/Net/Converters/ImageConverter.cs b/src/Discord.Net/Net/Converters/ImageConverter.cs index a40b5bf86..3446d2b2e 100644 --- a/src/Discord.Net/Net/Converters/ImageConverter.cs +++ b/src/Discord.Net/Net/Converters/ImageConverter.cs @@ -1,5 +1,4 @@ -using Discord.API; -using Newtonsoft.Json; +using Newtonsoft.Json; using System; using System.IO; @@ -20,8 +19,6 @@ namespace Discord.Net.Converters public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - if (value is Optional) - value = (Optional)value; var stream = value as Stream; byte[] bytes = new byte[stream.Length - stream.Position]; diff --git a/src/Discord.Net/Net/Converters/OptionalConverter.cs b/src/Discord.Net/Net/Converters/OptionalConverter.cs index a1e7c7543..260d642d4 100644 --- a/src/Discord.Net/Net/Converters/OptionalConverter.cs +++ b/src/Discord.Net/Net/Converters/OptionalConverter.cs @@ -5,20 +5,36 @@ namespace Discord.Net.Converters { public class OptionalConverter : JsonConverter { - public static readonly OptionalConverter Instance = new OptionalConverter(); + public static OptionalConverter Instance; + + private readonly JsonConverter _innerConverter; public override bool CanConvert(Type objectType) => true; public override bool CanRead => true; public override bool CanWrite => true; + public OptionalConverter(JsonConverter innerConverter) + { + _innerConverter = innerConverter; + } + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - return new Optional(serializer.Deserialize(reader)); + T obj; + if (_innerConverter != null) + obj = (T)_innerConverter.ReadJson(reader, typeof(T), null, serializer); + else + obj = serializer.Deserialize(reader); + return new Optional(obj); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - serializer.Serialize(writer, ((Optional)value).Value); + value = ((Optional)value).Value; + if (_innerConverter != null) + _innerConverter.WriteJson(writer, value, serializer); + else + serializer.Serialize(writer, value, typeof(T)); } } }