获取方法的委托的是通过一个ReflectionUtil获得的,该类主要用来优化反射,它通过Expression,可以将MethodInfo编译成Func<object,object[],object>委托,为Type编译一个Func<object>委托,用于创建实例对象。
通过Expression优化反射
Expression(表达式树)允许我们将代码逻辑以表达式的形式存储在树状结构里,然后在运行时去动态解析,实现动态编辑和执行代码。熟悉ORM框架的朋友对Expression肯定很熟悉,因为大部分方法都有一个Expression<TDelegate>类型的参数。访问关系型数据库的本质还是sql语句,orm的工作就是为开发人员屏蔽这个过程,以面向对象的方式去读写数据库,而不是自己编写sql语句。例如,Users.Where(u => u.Age > 18) 就可查询年龄大于18的用户。这里不对应用在orm的过程进行详解,下面我们介绍如何用Expression并利用它来生成委托。
.net定义了许多表达式类型,这些类型都派生自Expression,Expression是一个抽象类,而且是一个工厂类,所有类型的表达式都通过它来创建。如图:
先看一个 1 * 2 + 2 例子,我们用表达树来描述来描述它:
/*
* a * b + 2
*/
/*
直接操作
int a = 1, b = 2;
int result = a * 2 + 2;
*/
/*
通过委托调用
Func<int, int, int> func = new Func<int, int, int>((a, b) => { return a * b + 2; });
func(1, 2);
*/
/*通过Expression调用*/
//定义两个参数
ParameterExpression pe1 = Expression.Parameter(typeof(int), "a");
ParameterExpression pe2 = Expression.Parameter(typeof(int), "b");
//定义一个常量
ConstantExpression constExpression = Expression.Constant(2);
//参数数组
ParameterExpression[] parametersExpression = new ParameterExpression[]{pe1,pe2};
//一个乘法运算
BinaryExpression multiplyExpression = Expression.Multiply(pe1, pe2);
//一个加法运算
BinaryExpression unaryExpression = Expression.Add(multiplyExpression, constExpression);
//将上面的表达式转换为一个委托表达式
LambdaExpression lambdaExpression = Expression.Lambda<Func<int, int, int>>(unaryExpression, parametersExpression);
//将委托编译成可执行代码
Func<int,int,int> func = lambdaExpression.Compile() as Func<int,int,int>;
Console.WriteLine(func(1, 2));
可以看到我们最终将其编译为一个具体类型的委托了。下面看我们真正用到的方法是如何实现的,代码如下:
public static Func<object, object[], object> GetMethodDelegate(MethodInfo methodInfo)
{
if (methodInfo == null)
{
throw new ArgumentNullException("methodInfo");
}
//定义参数表达式,它表示委托的第一个参数
ParameterExpression instanceExp = Expression.Parameter(typeof(object), "instance");
//定义参数表达式,它表示委托的第二个参数
ParameterExpression paramExp = Expression.Parameter(typeof(object[]), "parameters");
//获取方法的参数信息数组
ParameterInfo[] paramInfos = methodInfo.GetParameters();
//参数表达式集合
List<Expression> paramExpList = new List<Expression>();
int length = paramInfos.Length;
for (int i = 0; i < length; i++)
{
//获取paramExp参数数组的第i个元素
BinaryExpression valueObj = Expression.ArrayIndex(paramExp, Expression.Constant(i));
//将其转换为与参数类型一致的类型
UnaryExpression valueCast = Expression.Convert(valueObj, paramInfos[i].ParameterType);
//添加到参数集合
paramExpList.Add(valueCast);
}
//方法所属的实例的表达式,如果为静态则为null
UnaryExpression instanceCast = methodInfo.IsStatic ? null : Expression.Convert(instanceExp, methodInfo.ReflectedType);
//表示调用方法的表达式
MethodCallExpression methodCall = Expression.Call(instanceCast, methodInfo, paramExpList);
//将表达式目录描述的lambda编译为可执行代码(委托)
if (methodCall.Type == typeof(void))
{
Expression<Action<object, object[]>> lambda = Expression.Lambda<Action<object, object[]>>(methodCall, instanceExp, paramExp);
Action<object, object[]> action = lambda.Compile();
return (instance, parameters) =>
{
action(instance, parameters);
return null;
};
}
else
{
UnaryExpression castMethodCall = Expression.Convert(methodCall, typeof(object));
Expression<Func<object, object[], object>> lambda = Expression.Lambda<Func<object, object[], object>>(castMethodCall, instanceExp, paramExp);
return lambda.Compile();
}
}









