using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Security.Cryptography; using System.Text; namespace FreeSql.Extensions.DynamicEntity { /// /// 动态创建对象帮助类 /// public class DynamicCompileHelper { /// /// 动态构建Class - Type /// /// public static DynamicCompileBuilder DynamicBuilder() { return new DynamicCompileBuilder(); } /// /// 委托缓存 /// private static readonly ConcurrentDictionary DelegateCache = new ConcurrentDictionary(); /// /// 设置动态对象的属性值 /// /// /// /// public static object CreateObjectByType(Type type, Dictionary porpertys) { if (type == null) return null; object istance = Activator.CreateInstance(type); if (istance == null) return null; //根据key确定缓存 var cacheKeyStr = string.Join("-", porpertys.Keys.OrderBy(s => s)); var dicKey = Md5Encryption(cacheKeyStr); var cacheKey = $"{type.GetHashCode()}-{dicKey}"; var dynamicDelegate = DelegateCache.GetOrAdd(cacheKey, key => { //表达式目录树构建委托 var typeParam = Expression.Parameter(type); var dicParamType = typeof(Dictionary); var dicParam = Expression.Parameter(dicParamType); var exps = new List(); var tempRef = Expression.Variable(typeof(object)); foreach (var pinfo in porpertys) { var propertyInfo = type.GetProperty(pinfo.Key); if (propertyInfo == null) continue; var propertyName = Expression.Constant(pinfo.Key, typeof(string)); exps.Add(Expression.Call(dicParam, dicParamType.GetMethod("TryGetValue"), propertyName, tempRef)); exps.Add(Expression.Assign(Expression.MakeMemberAccess(typeParam, propertyInfo), Expression.Convert(tempRef, propertyInfo.PropertyType))); exps.Add(Expression.Assign(tempRef, Expression.Default(typeof(object)))); } var returnTarget = Expression.Label(type); exps.Add(Expression.Return(returnTarget, typeParam)); exps.Add(Expression.Label(returnTarget, Expression.Default(type))); var block = Expression.Block(new[] { tempRef }, exps); var @delegate = Expression.Lambda(block, typeParam, dicParam).Compile(); return @delegate; }); var dynamicInvoke = dynamicDelegate.DynamicInvoke(istance, porpertys); return dynamicInvoke; } private static string Md5Encryption(string inputStr) { var result = string.Empty; //32位大写 using (var md5 = MD5.Create()) { var resultBytes = md5.ComputeHash(Encoding.UTF8.GetBytes(inputStr)); result = BitConverter.ToString(resultBytes); } return result; } } }