using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; namespace TouchSocket.Core { /// /// 动态成员访问器 /// /// public class MemberAccessor : MemberAccessor { /// /// 动态成员访问器 /// public MemberAccessor() : base(typeof(T)) { } } /// /// 动态成员访问器 /// public class MemberAccessor : IMemberAccessor { Func GetValueDelegate; Action SetValueDelegate; /// /// 动态成员访问器 /// /// public MemberAccessor(Type type) { Type = type; this.OnGetFieldInfes = (t) => { return t.GetFields(); }; this.OnGetProperties = (t) => { return t.GetProperties(); }; } private Dictionary dicFieldInfes; private Dictionary dicProperties; /// /// 构建 /// public void Build() { if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) { dicFieldInfes = this.OnGetFieldInfes.Invoke(Type).ToDictionary(a => a.Name); dicProperties = this.OnGetProperties.Invoke(Type).ToDictionary(a => a.Name); } GetValueDelegate = GenerateGetValue(); SetValueDelegate = GenerateSetValue(); } /// /// 获取属性 /// public Func OnGetProperties { get; set; } /// /// 获取字段 /// public Func OnGetFieldInfes { get; set; } /// /// 所属类型 /// public Type Type { get; } /// public object GetValue(object instance, string memberName) { return GetValueDelegate(instance, memberName); } /// public void SetValue(object instance, string memberName, object newValue) { SetValueDelegate(instance, memberName, newValue); } private Func GenerateGetValue() { if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) { return (obj, key) => { if (dicFieldInfes.TryGetValue(key, out var value1)) { return value1.GetValue(obj); } if (dicProperties.TryGetValue(key, out var value2)) { return value2.GetValue(obj); } return default; }; } var instance = Expression.Parameter(typeof(object), "instance"); var memberName = Expression.Parameter(typeof(string), "memberName"); var nameHash = Expression.Variable(typeof(int), "nameHash"); var calHash = Expression.Assign(nameHash, Expression.Call(memberName, typeof(object).GetMethod("GetHashCode"))); var cases = new List(); foreach (var propertyInfo in this.OnGetFieldInfes.Invoke(Type)) { var property = Expression.Field(Expression.Convert(instance, Type), propertyInfo.Name); var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); cases.Add(Expression.SwitchCase(Expression.Convert(property, typeof(object)), propertyHash)); } foreach (var propertyInfo in this.OnGetProperties.Invoke(Type)) { var property = Expression.Property(Expression.Convert(instance, Type), propertyInfo.Name); var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); cases.Add(Expression.SwitchCase(Expression.Convert(property, typeof(object)), propertyHash)); } if (cases.Count == 0) { return (a, b) => default; } var switchEx = Expression.Switch(nameHash, Expression.Constant(null), cases.ToArray()); var methodBody = Expression.Block(typeof(object), new[] { nameHash }, calHash, switchEx); return Expression.Lambda>(methodBody, instance, memberName).Compile(); } private Action GenerateSetValue() { if (GlobalEnvironment.OptimizedPlatforms.HasFlag(OptimizedPlatforms.Unity)) { return (obj, key, value) => { if (dicFieldInfes.TryGetValue(key, out var value1)) { value1.SetValue(obj, value); } if (dicProperties.TryGetValue(key, out var value2)) { value2.SetValue(obj, value); } }; } var instance = Expression.Parameter(typeof(object), "instance"); var memberName = Expression.Parameter(typeof(string), "memberName"); var newValue = Expression.Parameter(typeof(object), "newValue"); var nameHash = Expression.Variable(typeof(int), "nameHash"); var calHash = Expression.Assign(nameHash, Expression.Call(memberName, typeof(object).GetMethod("GetHashCode"))); var cases = new List(); foreach (var propertyInfo in this.OnGetFieldInfes.Invoke(Type)) { var property = Expression.Field(Expression.Convert(instance, Type), propertyInfo.Name); var setValue = Expression.Assign(property, Expression.Convert(newValue, propertyInfo.FieldType)); var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); cases.Add(Expression.SwitchCase(Expression.Convert(setValue, typeof(object)), propertyHash)); } foreach (var propertyInfo in this.OnGetProperties(Type)) { if (!propertyInfo.CanWrite) { continue; } var property = Expression.Property(Expression.Convert(instance, Type), propertyInfo.Name); var setValue = Expression.Assign(property, Expression.Convert(newValue, propertyInfo.PropertyType)); var propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int)); cases.Add(Expression.SwitchCase(Expression.Convert(setValue, typeof(object)), propertyHash)); } if (cases.Count == 0) { return (a, b, c) => { }; } var switchEx = Expression.Switch(nameHash, Expression.Constant(null), cases.ToArray()); var methodBody = Expression.Block(typeof(object), new[] { nameHash }, calHash, switchEx); return Expression.Lambda>(methodBody, instance, memberName, newValue).Compile(); } } }