12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485 |
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- using System.Text;
- using System.Threading.Tasks;
- namespace EasyDevCore.Common.Caches
- {
- /// <summary>
- ///
- /// </summary>
- public static class ExpressionCache
- {
- /// <summary>
- ///
- /// </summary>
- /// <param name="dictionary">The dictionary.</param>
- /// <param name="o">The o.</param>
- public delegate void AppendToDictionary(IDictionary<string, object> dictionary, object o);
- /// <summary>
- /// The s type cache
- /// </summary>
- static readonly ConcurrentDictionary<Type, AppendToDictionary> s_typeCache = new ConcurrentDictionary<Type, AppendToDictionary>();
- /// <summary>
- /// The dictionary indexer property
- /// </summary>
- private static readonly PropertyInfo _dictionaryIndexerProperty = GetDictionaryIndexer();
- /// <summary>
- /// Gets the or create append to dictionary method.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns></returns>
- public static AppendToDictionary GetOrCreateAppendToDictionaryMethod(Type type) => s_typeCache.GetOrAdd(type, t => CreateAppendToDictionaryMethod(t));
- /// <summary>
- /// Creates the append to dictionary method.
- /// </summary>
- /// <param name="type">The type.</param>
- /// <returns></returns>
- private static AppendToDictionary CreateAppendToDictionaryMethod(Type type)
- {
- var dictionaryParameter = Expression.Parameter(typeof(IDictionary<string, object>), "dictionary");
- var objectParameter = Expression.Parameter(typeof(object), "o");
- var castedParameter = Expression.Convert(objectParameter, type); // cast o to the actual type
- // Create setter for each properties
- // dictionary["PropertyName"] = o.PropertyName;
- var properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
- var setters =
- from prop in properties
- where prop.CanRead
- let indexerExpression = Expression.Property(dictionaryParameter, _dictionaryIndexerProperty, Expression.Constant(prop.Name))
- let getExpression = Expression.Property(castedParameter, prop.GetMethod)
- select Expression.Assign(indexerExpression, getExpression);
- var body = new List<Expression>(properties.Length + 1);
- body.Add(castedParameter);
- body.AddRange(setters);
- var lambdaExpression = Expression.Lambda<AppendToDictionary>(Expression.Block(body), dictionaryParameter, objectParameter);
- return lambdaExpression.Compile();
- }
- // Get the PropertyInfo for IDictionary<string, object>.this[string key]
- /// <summary>
- /// Gets the dictionary indexer.
- /// </summary>
- /// <returns></returns>
- private static PropertyInfo GetDictionaryIndexer()
- {
- var indexers = from prop in typeof(IDictionary<string, object>).GetProperties(BindingFlags.Instance | BindingFlags.Public)
- let indexParameters = prop.GetIndexParameters()
- where indexParameters.Length == 1 && typeof(string).IsAssignableFrom(indexParameters[0].ParameterType)
- select prop;
- return indexers.Single();
- }
- }
- }
|