using System; using System.Collections.Concurrent; using System.Linq; using System.Linq.Expressions; using System.Reflection; using Newtonsoft.Json; namespace VCommon.VAutoMapper.Internals { internal static class JsonConvertHolder { private static readonly ConcurrentDictionary ConverterInstances = new ConcurrentDictionary(); private static readonly ConcurrentDictionary, Expression>> CachedDeserializationExpression = new ConcurrentDictionary, Expression>>(); private static readonly ConcurrentDictionary, Expression>> CachedSerializationExpression = new ConcurrentDictionary, Expression>>(); private static JsonConverter GetConverterInstance(Type converterType) { if (ConverterInstances.TryGetValue(converterType, out var instance)) return instance; instance = Activator.CreateInstance(converterType) as JsonConverter; ConverterInstances[converterType] = instance ?? throw new ArgumentException($"type must extend from {nameof(JsonConverter)}"); return instance; } public static Expression> GetDeserializationExpression(PropertyInfo fromProp, PropertyInfo toProp) { var pair = new Tuple(fromProp, toProp); if (CachedDeserializationExpression.TryGetValue(pair, out var exp)) return exp; var attr = toProp.GetCustomAttribute(); if (0 == attr.Converters.Count) { exp = (s, t) => JsonConvert.DeserializeObject(s, t); CachedDeserializationExpression[pair] = exp; } else { var converters = attr.Converters.Select(GetConverterInstance).ToArray(); var setting = new JsonSerializerSettings { Converters = converters }; exp = CachedDeserializationExpression[pair] = (s, t) => JsonConvert.DeserializeObject(s, t, setting); } return exp; } public static Expression> GetSerializationExpression(PropertyInfo fromProp, PropertyInfo toProp) { var pair = new Tuple(fromProp, toProp); if (CachedSerializationExpression.TryGetValue(pair, out var exp)) return exp; var attr = fromProp.GetCustomAttribute(); if (0 == attr.Converters.Count) { exp = CachedSerializationExpression[pair] = o => JsonConvert.SerializeObject(o); } else { var converters = attr.Converters.Select(GetConverterInstance).ToArray(); var setting = new JsonSerializerSettings { Converters = converters }; exp = CachedSerializationExpression[pair] = o => JsonConvert.SerializeObject(o, setting); } return exp; } } }