C#表达式目录树系列之2 --常见的表达式目录树的实例

概要

本文主要列举出一些常用的表达式目录树实例,便于以此为基础,构建更复杂的表达式目录树,以满足各种多变的业务场景。

表达式目录树的构建,除了使用Expression类提供的静态方法外,一般还需要同反射结合在一起。例如通过反射找到类中具体定义的方法,通过反射找到类中的构造函数等。

常用表达式目录树构建实例

Student类的定义详见附录。

访问对象的属性

构建目标 s => s.FirstName s是Student类型
代码如下:

ParameterExpression sParameter = Expression.Parameter(typeof(Student), "s");
MemberExpression firstNameExpression = Expression.Property(sParameter,typeof(Student).GetProperty("FirstName"));
LambdaExpression  lengthLambdaExpression = Expression.Lambda<Func<Student,string>>(firstNameExpression,sParameter);	
Console.WriteLine(lengthLambdaExpression);
var lengthDelegate = (Func<Student,string>) lengthLambdaExpression.Compile();
Console.WriteLine(lengthDelegate.Invoke(new Student("Tom","Green",14)));

代码执行流程为:

  1. 构建Lambda表达式中的变量s
  2. 构建表达式目录树s.FirstName
  3. 调用LambdaExpression的Lambda方法生成表达式: s => s.FirstName
  4. 调用LambdaExpression的Compile方法生成委托对象
  5. 委托对象调用Invoke方法,执行 s.FirstName代码。

访问嵌套对象属性

构建目标 s => s.FirstName.Length s是Student类型

ParameterExpression sParameter = Expression.Parameter(typeof(Student), "s");
MemberExpression firstNameExpression = Expression.Property(sParameter,typeof(Student).GetProperty("FirstName"));
MemberExpression lengthExpression = Expression.Property(firstNameExpression,typeof(string).GetProperty("Length"));
LambdaExpression  lengthLambdaExpression = Expression.Lambda<Func<Student,int>>(lengthExpression,sParameter);	
Console.WriteLine(lengthLambdaExpression);
var lengthDelegate = (Func<Student,int>) lengthLambdaExpression.Compile();
Console.WriteLine(lengthDelegate.Invoke(new Student("Tom","Green",14)));

访问对象的方法

构建目标: s => s.GetFullName() s是Student类型

ParameterExpression sParameter = Expression.Parameter(typeof(Student),"s");
MethodCallExpression getFullNameMethod = Expression.Call(
		sParameter,
		typeof(Student).GetMethod("GetFullName",new Type[]{}), // method
		new Expression[] // Work method's parameter
		{
		}
	);	
LambdaExpression  lambdaGetFullNameMethod = Expression.Lambda<Func<Student,string>>(getFullNameMethod,sParameter);
Console.WriteLine(lambdaGetFullNameMethod);
var lambdaGetFullNameDelegate = (Func<Student,string>) lambdaGetFullNameMethod.Compile();
Console.WriteLine(lambdaGetFullNameDelegate.Invoke(new Student("Tom", "Green", 13)));

访问对象方法(含参数)

构建目标:m => m.GetFullName(“Mr”) m是Student类型

ParameterExpression mParameter = Expression.Parameter(typeof(Student),"m");
string prefix = "Mr";
MethodCallExpression getFullNameMethod = Expression.Call(
		mParameter,
		typeof(Student).GetMethod("GetFullName", new Type[]{typeof(string)}), // method
		new Expression[] // Work method's parameter
		{
			Expression.Constant(prefix)
		}
	);

LambdaExpression  lambdaGetFullNameMethod = Expression.Lambda<Func<Student,string>>(getFullNameMethod,mParameter);
Console.WriteLine(lambdaGetFullNameMethod);
var lambdaGetFullNameDelegate = (Func<Student,string>) lambdaGetFullNameMethod.Compile();
Console.WriteLine(lambdaGetFullNameDelegate.Invoke(new Student("Tom", "Green", 13)));
		

访问类中静态方法

调用string类的Concat方法实现字符串拼接。
构建目标:c => Concat(c.FirstName, c.LastName) c是Student类型

ParameterExpression cParameter = Expression.Parameter(typeof(Student),"c");
MemberExpression firstNameExpression = Expression.Property(cParameter, typeof(Student).GetProperty("FirstName"));
MemberExpression lastNameExpression = Expression.Property(cParameter, typeof(Student).GetProperty("LastName"));
MethodCallExpression ConcatMethod = Expression.Call(
		typeof(string).GetMethod("Concat", BindingFlags.Public | BindingFlags.Static, null,  CallingConventions.Any, new Type[]{typeof(string),typeof(string)}, null), // method
		new Expression[] // Work method's parameter
		{
			firstNameExpression,
			lastNameExpression
		}
	);
LambdaExpression  lambdaConcatMethod = Expression.Lambda<Func<Student,string>>(ConcatMethod,cParameter);
Console.WriteLine(lambdaConcatMethod);
var lambdaConcatDelegate = (Func<Student,string>) lambdaConcatMethod.Compile();
Console.WriteLine(lambdaConcatDelegate.Invoke(new Student("Tom", "Green", 13)));

调用类中含参数的构造方法创建实例

构建目标:(n, l, m) => new Student(n, l, m)
n,l为string类型,m是int类型

ParameterExpression n = Expression.Parameter(typeof(string),"n");
ParameterExpression l = Expression.Parameter(typeof(string),"l");
ParameterExpression m = Expression.Parameter(typeof(int),"m");
ConstructorInfo ctor = typeof(Student).GetConstructor(
		BindingFlags.Instance | BindingFlags.Public, 
		null, 
		CallingConventions.HasThis, 
		new[] { typeof(string),typeof(string), typeof(int) }, new ParameterModifier[] {}
	);
var expressionNew = Expression.New(ctor,new Expression[]{n,l,m});
LambdaExpression  newLambda = Expression.Lambda<Func<string,string,int,Student>>(expressionNew, new ParameterExpression[]{n,l,m});
Console.WriteLine(newLambda);
var newDelegate = (Func<string,string,int,Student>) newLambda.Compile();
Console.WriteLine(newDelegate.Invoke("Tom","Green",13).GetFullName());

调用类中构造方法创建实例并给属性赋值

调用Student类的无参构造函数创建实例,并将已有Student实例中的属性值赋值给新创建的实例。
构建目标:r => new Student() {FirstName = r.FirstName, LastName = r.LastName, Age = r.Age} r为Student类型

Student stuResource = new Student("Jack", "Green",12);
ParameterExpression r = Expression.Parameter(typeof(Student),"r");
ConstructorInfo ctor = typeof(Student).GetConstructor(
		BindingFlags.Instance | BindingFlags.Public, 
		null, 
		CallingConventions.HasThis, 
		new Type [] {  }, new ParameterModifier[] {}
	);
List<MemberBinding> bindings = new List<MemberBinding>();
foreach(PropertyInfo info in typeof(Student).GetProperties()){
	MemberExpression rMember = Expression.Property(r,typeof(Student).GetProperty(info.Name));
	MemberBinding binding = Expression.Bind(info,rMember);
	bindings.Add(binding);
}	
MemberInitExpression memberInitExpression = 	MemberInitExpression memberInitExpression = Expression.MemberInit( Expression.New(ctor, Array.Empty<Expression>()), bindings.ToArray());	
LambdaExpression  lambdaStudentNewExpression = Expression.Lambda<Func<Student,Student>>(memberInitExpression,r);	
Console.WriteLine(lambdaStudentNewExpression);
var lambdaStudentNewDelegate = (Func<Student,Student>) lambdaStudentNewExpression.Compile();
Console.WriteLine(lambdaStudentNewDelegate.Invoke(stuResource).GetFullName());

嵌套调用方法

构建目标: c => Concat(c.GetFullName(), c.LastName) c为Student类型

ParameterExpression cParameter = Expression.Parameter(typeof(Student),"c");
MethodCallExpression getFullNameMethod = Expression.Call(
	    cParameter,
		typeof(Student).GetMethod("GetFullName", new Type[]{}, null), // method
		new Expression[] // Work method's parameter
		{
			
		}
	);
MemberExpression lastNameExpression = Expression.Property(cParameter, typeof(Student).GetProperty("LastName"));
MethodCallExpression ConcatMethod = Expression.Call(
		typeof(string).GetMethod("Concat", BindingFlags.Public | BindingFlags.Static, null,  CallingConventions.Any, new Type[]{typeof(string),typeof(string)}, null), // method
		new Expression[] // Work method's parameter
		{
			getFullNameMethod,
			lastNameExpression
		}
	);
LambdaExpression  lambdaConcatMethod = Expression.Lambda<Func<Student,string>>(ConcatMethod, cParameter);
Console.WriteLine(lambdaConcatMethod);
var lambdaConcatDelegate = (Func<Student,string>) lambdaConcatMethod.Compile();
Console.WriteLine(lambdaConcatDelegate.Invoke(new Student("Tom", "Green", 13)));

附录

public class Student {
	public Student(string firstName, string lastName, int age){
		this.FirstName = firstName;
		this.LastName = lastName;
		this.Age = age;
	}
	public Student(){
	}
	public string FirstName {get;set;}
	public string LastName {get;set;}
	public int Age {get;set;}
	public string GetFullName(){
		return FirstName +  ", " +  LastName;
	}
	public string GetFullName(string prefix){
		return prefix + " " + FirstName +  ", " +  LastName;
	}
}

表达式目录树系列全部文章

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
C# 中的表达式目录(Expression Tree)是一个抽象语法(AST),可以表示一个 C# 表达式的结构和含义。它们提供了一种将代码表示为数据的方式,可以用于编写动态查询、ORM 映射、编译器、代码生成器等工具。 表达式目录是由 Expression 类型的对象组成的,每个对象都代表了一个 C# 表达式的一部分。例如,一个二元运算符表达式可以表示为一个 BinaryExpression 类型的对象,它包含了左右操作数和运算符等信息。 表达式目录可以通过编写 Lambda 表达式来创建。Lambda 表达式是一种匿名函数,可以将其编译成表达式目录。例如,以下代码创建了一个表示加法的表达式目录: ``` Expression<Func<int, int, int>> addExpr = (x, y) => x + y; ``` 这个表达式目录表示了一个接受两个 int 类型参数并返回 int 类型结果的函数,函数体是 x + y。 表达式目录也可以用于动态构建 LINQ 查询。例如,以下代码构建了一个查询,查询所有 age 大于 18 的人: ``` var people = new List<Person> { ... }; var paramExpr = Expression.Parameter(typeof(Person), "p"); var agePropExpr = Expression.Property(paramExpr, "Age"); var ageConstExpr = Expression.Constant(18, typeof(int)); var greaterThanExpr = Expression.GreaterThan(agePropExpr, ageConstExpr); var lambdaExpr = Expression.Lambda<Func<Person, bool>>(greaterThanExpr, paramExpr); var query = people.AsQueryable().Where(lambdaExpr); ``` 这个代码通过表达式目录构建了一个 Lambda 表达式,查询所有 age 大于 18 的人。其中,Expression.Parameter() 方法创建了一个表示 Person 类型的参数,Expression.Property() 方法创建了一个表示 Age 属性的表达式,Expression.Constant() 方法创建了一个表示常量值的表达式,Expression.GreaterThan() 方法创建了一个表示大于运算的表达式,Expression.Lambda() 方法将这些表达式组合成一个 Lambda 表达式表达式目录可以在编译时或运行时进行解析和执行。例如,以下代码编译并执行了一个表示加法的表达式目录: ``` var addExpr = Expression.Add(Expression.Constant(1), Expression.Constant(2)); var addFunc = Expression.Lambda<Func<int>>(addExpr).Compile(); var result = addFunc(); // 3 ``` 这个代码创建了一个表示加法的表达式目录,然后将其编译成一个函数(addFunc),最后执行这个函数得到结果(result)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值