Created
January 14, 2017 08:09
-
-
Save Yortw/e568b363405577d55d1b68cad8279851 to your computer and use it in GitHub Desktop.
UWP Json.Net CachedReflection Converter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public sealed class CachedReflectionJsonConverter : JsonConverter | |
{ | |
private IEnumerable<Type> _HandledTypes; | |
private static Dictionary<Type, CachedTypeInformation> _ReflectionCache = new Dictionary<Type, CachedTypeInformation>(); | |
public CachedReflectionJsonConverter(IEnumerable<Type> handledTypes) | |
{ | |
_HandledTypes = handledTypes.ToArray(); | |
} | |
public override bool CanConvert(Type objectType) | |
{ | |
return _HandledTypes.Contains(objectType); | |
} | |
public override bool CanRead | |
{ | |
get | |
{ | |
return true; | |
} | |
} | |
public override bool CanWrite | |
{ | |
get | |
{ | |
return false; | |
} | |
} | |
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) | |
{ | |
CachedTypeInformation cachedInfo = null; | |
if (!_ReflectionCache.TryGetValue(objectType, out cachedInfo)) | |
{ | |
cachedInfo = new CachedTypeInformation(); | |
cachedInfo.WriteableProperties = | |
( | |
from p | |
in objectType.GetProperties(BindingFlags.Public | BindingFlags.Instance) | |
where p.CanWrite | |
select p | |
).ToDictionary((p) => p.Name, StringComparer.OrdinalIgnoreCase); | |
cachedInfo.Constructor = objectType.GetConstructor(Type.EmptyTypes); | |
_ReflectionCache[objectType] = cachedInfo; | |
} | |
var retVal = cachedInfo.Constructor.Invoke(null); | |
PropertyInfo propertyInfo = null; | |
var moreToRead = reader.Read(); | |
while (moreToRead && reader.TokenType != JsonToken.EndObject) | |
{ | |
if (reader.TokenType == JsonToken.PropertyName) | |
{ | |
var name = (string)reader.Value; | |
cachedInfo.WriteableProperties.TryGetValue(name, out propertyInfo); | |
moreToRead = reader.Read(); | |
if (propertyInfo != null) | |
{ | |
switch (reader.TokenType) | |
{ | |
case JsonToken.String: | |
propertyInfo.SetValue(retVal, reader.Value); | |
break; | |
case JsonToken.Float: | |
case JsonToken.Integer: | |
case JsonToken.Boolean: | |
case JsonToken.Date: | |
if (propertyInfo.PropertyType == typeof(decimal)) | |
propertyInfo.SetValue(retVal, System.Convert.ChangeType(reader.Value, propertyInfo.PropertyType)); | |
else if (reader.TokenType == JsonToken.Integer && propertyInfo.PropertyType != typeof(Int64)) | |
propertyInfo.SetValue(retVal, System.Convert.ChangeType(reader.Value, propertyInfo.PropertyType)); | |
else | |
propertyInfo.SetValue(retVal, reader.Value); | |
break; | |
case JsonToken.Null: | |
propertyInfo.SetValue(retVal, reader.Value); | |
break; | |
case JsonToken.StartObject: | |
case JsonToken.StartArray: | |
propertyInfo.SetValue(retVal, serializer.Deserialize(reader, propertyInfo.PropertyType)); | |
break; | |
default: | |
throw new InvalidOperationException(); | |
} | |
} | |
} | |
moreToRead = reader.Read(); | |
} | |
return retVal; | |
} | |
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) | |
{ | |
throw new NotImplementedException(); | |
} | |
private sealed class CachedTypeInformation | |
{ | |
public ConstructorInfo Constructor { get; set; } | |
public Dictionary<string, PropertyInfo> WriteableProperties { get; set; } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This can be further improved by dumping the 'handledTypes' stuff and either applying the converter as an attribute to your entity classes or if that's not posible implementing a custom contract coverter (http://www.newtonsoft.com/json/help/html/Performance.htm).