利用lambda表达式树优化反射详解

2020-01-05 10:10:10丽君

但是对于只是简单的SetValue或者GetValue,包括用反射构造函数,我们可以想一个中继的方法,那就是使用表达式树。对于不理解表达式树的,可以到微软文档查看,点击我。表达式树很容易通过对象模型表示表达式,因此强烈建议学习。查看以下代码:


static void Main()
 {
  Dog dog = new Dog();
  PropertyInfo propertyInfo = dog.GetType().GetProperty(nameof(dog.Name)); //获取对象Dog的属性
  MethodInfo SetterMethodInfo = propertyInfo.GetSetMethod(); //获取属性Name的set方法

  ParameterExpression param = Expression.Parameter(typeof(Dog), "param");
  Expression GetPropertyValueExp = Expression.Lambda(Expression.Property(param, nameof(dog.Name)), param);
  Expression<Func<Dog, String>> GetPropertyValueLambda = (Expression<Func<Dog, String>>)GetPropertyValueExp;
  ParameterExpression paramo = Expression.Parameter(typeof(Dog), "param");
  ParameterExpression parami = Expression.Parameter(typeof(String), "newvalue");
  MethodCallExpression MethodCallSetterOfProperty = Expression.Call(paramo, SetterMethodInfo, parami);
  Expression SetPropertyValueExp = Expression.Lambda(MethodCallSetterOfProperty, paramo, parami);
  Expression<Action<Dog, String>> SetPropertyValueLambda = (Expression<Action<Dog, String>>)SetPropertyValueExp;

  //创建了属性Name的Get方法表达式和Set方法表达式,当然只是最简单的
  Func<Dog, String> Getter = GetPropertyValueLambda.Compile(); 
  Action<Dog, String> Setter = SetPropertyValueLambda.Compile();

  Setter?.Invoke(dog, "WLJ"); //我们现在对dog这个对象的Name属性赋值
  String dogName = Getter?.Invoke(dog); //获取属性Name的值
  
  Console.WriteLine(dogName);
  Console.ReadKey();
 }

 public class Dog
 {
  public String Name { get; set; }
 }

以下代码可能很难看得懂,但只要知道我们创建了属性的Get、Set这两个方法就行,其结果最后也能输出狗的名字 WLJ,拥有ExpressionTree的好处是他有一个名为Compile()的方法,它创建一个代表表达式的代码块。现在是最有趣的部分,假设你在编译时不知道类型(在这篇文章中包含的代码我在不同的程序集上创建了一个类型)你仍然可以应用这种技术,我将对于常用的属性的set,get操作进行分装。


/// <summary>
   /// 属性类,仿造反射中的PropertyInfo
 /// </summary>
   public class Property
 {

  private readonly PropertyGetter getter;
  private readonly PropertySetter setter;
  public String Name { get; private set; }

  public PropertyInfo Info { get; private set; }

  public Property(PropertyInfo propertyInfo)
  {
   if (propertyInfo == null)
    throw new NullReferenceException("属性不能为空");
   this.Name = propertyInfo.Name;
   this.Info = propertyInfo;
   if (this.Info.CanRead)
   {
    this.getter = new PropertyGetter(propertyInfo);
   }

   if (this.Info.CanWrite)
   {
    this.setter = new PropertySetter(propertyInfo);
   }
  }


  /// <summary>
     /// 获取对象的值
  /// </summary>
    /// <param name="instance"></param>
    /// <returns></returns>
     public Object GetValue(Object instance)
  {
   return getter?.Invoke(instance);
  }


  /// <summary>
     /// 赋值操作
  /// </summary>
    /// <param name="instance"></param>
    /// <param name="value"></param>
     public void SetValue(Object instance, Object value)
  {
   this.setter?.Invoke(instance, value);
  }

  private static readonly ConcurrentDictionary<Type, Core.Reflection.Property[]> securityCache = new ConcurrentDictionary<Type, Property[]>();

  public static Core.Reflection.Property[] GetProperties(Type type)
  {
   return securityCache.GetOrAdd(type, t => t.GetProperties().Select(p => new Property(p)).ToArray());
  }

 }

  /// <summary>
   /// 属性Get操作类
  /// </summary>
    public class PropertyGetter
  {
  private readonly Func<Object, Object> funcGet;

  public PropertyGetter(PropertyInfo propertyInfo) : this(propertyInfo?.DeclaringType, propertyInfo.Name)
  {

  }

  public PropertyGetter(Type declareType, String propertyName)
  {
   if (declareType == null)
   {
    throw new ArgumentNullException(nameof(declareType));
   }
   if (propertyName == null)
   {
    throw new ArgumentNullException(nameof(propertyName));
   }



   this.funcGet = CreateGetValueDeleagte(declareType, propertyName);
  }


  //代码核心部分
     private static Func<Object, Object> CreateGetValueDeleagte(Type declareType, String propertyName)
  {
   // (object instance) => (object)((declaringType)instance).propertyName

       var param_instance = Expression.Parameter(typeof(Object));
   var body_objToType = Expression.Convert(param_instance, declareType);
   var body_getTypeProperty = Expression.Property(body_objToType, propertyName);
   var body_return = Expression.Convert(body_getTypeProperty, typeof(Object));
   return Expression.Lambda<Func<Object, Object>>(body_return, param_instance).Compile();
  }

  public Object Invoke(Object instance)
  {
   return this.funcGet?.Invoke(instance);
  }
 }


  public class PropertySetter
 {
  private readonly Action<Object, Object> setFunc;

  public PropertySetter(PropertyInfo property) 
  {
   if (property == null)

   {
    throw new ArgumentNullException(nameof(property));
   }
   this.setFunc = CreateSetValueDelagate(property);
  }



  private static Action<Object, Object> CreateSetValueDelagate(PropertyInfo property)
  {
   // (object instance, object value) => 
   //  ((instanceType)instance).Set_XXX((propertyType)value)

   //声明方法需要的参数
   var param_instance = Expression.Parameter(typeof(Object));
   var param_value = Expression.Parameter(typeof(Object));

   var body_instance = Expression.Convert(param_instance, property.DeclaringType);
   var body_value = Expression.Convert(param_value, property.PropertyType);
   var body_call = Expression.Call(body_instance, property.GetSetMethod(), body_value);

   return Expression.Lambda<Action<Object, Object>>(body_call, param_instance, param_value).Compile();
  }

  public void Invoke(Object instance, Object value)
  {
   this.setFunc?.Invoke(instance, value);
  }
 }