首页 > 代码库 > Util应用程序框架公共操作类(九):Lambda表达式扩展
Util应用程序框架公共操作类(九):Lambda表达式扩展
上一篇对Lambda表达式公共操作类进行了一些增强,本篇使用扩展方法对Lambda表达式进行扩展。
修改Util项目的Extensions.Expression.cs文件,代码如下。
using System;using System.Linq;using System.Linq.Expressions;using System.Reflection;using Util.Lambdas;namespace Util { /// <summary> /// 表达式扩展 /// </summary> public static partial class Extensions { #region Property(属性表达式) /// <summary> /// 创建属性表达式 /// </summary> /// <param name="expression">表达式</param> /// <param name="propertyName">属性名,支持多级属性名,与句点分隔,范例:Customer.Name</param> public static Expression Property( this Expression expression, string propertyName ) { if ( propertyName.All( t => t != ‘.‘ ) ) return Expression.Property( expression, propertyName ); var propertyNameList = propertyName.Split( ‘.‘ ); Expression result = null; for ( int i = 0; i < propertyNameList.Length; i++ ) { if ( i == 0 ) { result = Expression.Property( expression, propertyNameList[0] ); continue; } result = result.Property( propertyNameList[i] ); } return result; } /// <summary> /// 创建属性表达式 /// </summary> /// <param name="expression">表达式</param> /// <param name="member">属性</param> public static Expression Property( this Expression expression, MemberInfo member ) { return Expression.MakeMemberAccess( expression, member ); } #endregion #region Operation(操作) /// <summary> /// 操作 /// </summary> /// <param name="left">左操作数</param> /// <param name="operator">运算符</param> /// <param name="value">值</param> public static Expression Operation( this Expression left, Operator @operator, object value ) { switch ( @operator ) { case Operator.Equal: return left.Equal( value ); case Operator.NotEqual: return left.NotEqual( value ); case Operator.Greater: return left.Greater( value ); case Operator.Less: return left.Less( value ); case Operator.GreaterEqual: return left.GreaterEqual( value ); case Operator.LessEqual: return left.LessEqual( value ); case Operator.Contains: return left.Call( "Contains", value ); case Operator.Starts: return left.StartsWith( value ); case Operator.Ends: return left.EndsWith( value ); } throw new NotImplementedException(); } #endregion #region StartsWith(头匹配) /// <summary> /// 头匹配 /// </summary> /// <param name="left">左操作数</param> /// <param name="value">值</param> public static Expression StartsWith( this Expression left, object value ) { return left.Call( "StartsWith", new[] { typeof( string ) }, value ); } #endregion #region EndsWith(尾匹配) /// <summary> /// 尾匹配 /// </summary> /// <param name="left">左操作数</param> /// <param name="value">值</param> public static Expression EndsWith( this Expression left, object value ) { return left.Call( "EndsWith", new[] { typeof( string ) }, value ); } #endregion #region Call(调用方法表达式) /// <summary> /// 创建调用方法表达式 /// </summary> /// <param name="instance">调用的实例</param> /// <param name="methodName">方法名</param> /// <param name="values">参数值列表</param> public static Expression Call( this Expression instance, string methodName, params Expression[] values ) { return Expression.Call( instance, instance.Type.GetMethod( methodName ), values ); } /// <summary> /// 创建调用方法表达式 /// </summary> /// <param name="instance">调用的实例</param> /// <param name="methodName">方法名</param> /// <param name="values">参数值列表</param> public static Expression Call( this Expression instance, string methodName, params object[] values ) { if ( values == null || values.Length == 0 ) return Expression.Call( instance, instance.Type.GetMethod( methodName ) ); return Expression.Call( instance, instance.Type.GetMethod( methodName ), values.Select( Expression.Constant ) ); } /// <summary> /// 创建调用方法表达式 /// </summary> /// <param name="instance">调用的实例</param> /// <param name="methodName">方法名</param> /// <param name="paramTypes">参数类型列表</param> /// <param name="values">参数值列表</param> public static Expression Call( this Expression instance, string methodName, Type[] paramTypes, params object[] values ) { if ( values == null || values.Length == 0 ) return Expression.Call( instance, instance.Type.GetMethod( methodName, paramTypes ) ); return Expression.Call( instance, instance.Type.GetMethod( methodName, paramTypes ), values.Select( Expression.Constant ) ); } #endregion #region Equal(等于表达式) /// <summary> /// 创建等于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression Equal( this Expression left, Expression right ) { return Expression.Equal( left, right ); } /// <summary> /// 创建等于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="value">值</param> public static Expression Equal( this Expression left, object value ) { return left.Equal( Lambda.Constant( left, value ) ); } #endregion #region NotEqual(不等于表达式) /// <summary> /// 创建不等于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression NotEqual( this Expression left, Expression right ) { return Expression.NotEqual( left, right ); } /// <summary> /// 创建不等于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="value">值</param> public static Expression NotEqual( this Expression left, object value ) { return left.NotEqual( Lambda.Constant( left, value ) ); } #endregion #region Greater(大于表达式) /// <summary> /// 创建大于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression Greater( this Expression left, Expression right ) { return Expression.GreaterThan( left, right ); } /// <summary> /// 创建大于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="value">值</param> public static Expression Greater( this Expression left, object value ) { return left.Greater( Lambda.Constant( left, value ) ); } #endregion #region Less(小于表达式) /// <summary> /// 创建小于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression Less( this Expression left, Expression right ) { return Expression.LessThan( left, right ); } /// <summary> /// 创建小于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="value">值</param> public static Expression Less( this Expression left, object value ) { return left.Less( Lambda.Constant( left, value ) ); } #endregion #region GreaterEqual(大于等于表达式) /// <summary> /// 创建大于等于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression GreaterEqual( this Expression left, Expression right ) { return Expression.GreaterThanOrEqual( left, right ); } /// <summary> /// 创建大于等于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="value">值</param> public static Expression GreaterEqual( this Expression left, object value ) { return left.GreaterEqual( Lambda.Constant( left, value ) ); } #endregion #region LessEqual(小于等于表达式) /// <summary> /// 创建小于等于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression LessEqual( this Expression left, Expression right ) { return Expression.LessThanOrEqual( left, right ); } /// <summary> /// 创建小于等于运算表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="value">值</param> public static Expression LessEqual( this Expression left, object value ) { return left.LessEqual( Lambda.Constant( left, value ) ); } #endregion #region Compose(组合表达式) /// <summary> /// 组合表达式 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="first">左操作数</param> /// <param name="second">右操作数</param> /// <param name="merge">合并操作</param> internal static Expression<T> Compose<T>( this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge ) { var map = first.Parameters.Select( ( f, i ) => new { f, s = second.Parameters[i] } ).ToDictionary( p => p.s, p => p.f ); var secondBody = ParameterRebinder.ReplaceParameters( map, second.Body ); return Expression.Lambda<T>( merge( first.Body, secondBody ), first.Parameters ); } #endregion #region And(与表达式) /// <summary> /// 与操作表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression And( this Expression left, Expression right ) { if ( left == null ) return right; if ( right == null ) return left; return Expression.AndAlso( left, right ); } /// <summary> /// 与操作表达式 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression<Func<T, bool>> And<T>( this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right ) { if ( left == null ) return right; if ( right == null ) return left; return left.Compose( right, Expression.AndAlso ); } #endregion #region Or(或表达式) /// <summary> /// 或操作表达式 /// </summary> /// <param name="left">左操作数</param> /// <param name="right">右操作数</param> public static Expression Or( this Expression left, Expression right ) { return Expression.OrElse( left, right ); } /// <summary> /// 或操作表达式 /// </summary> /// <typeparam name="T">对象类型</typeparam> /// <param name="first">左操作数</param> /// <param name="second">右操作数</param> /// <returns></returns> public static Expression<Func<T, bool>> Or<T>( this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second ) { return first.Compose( second, Expression.OrElse ); } #endregion #region Value(获取lambda表达式的值) /// <summary> /// 获取lambda表达式的值 /// </summary> /// <typeparam name="T">对象类型</typeparam> public static object Value<T>( this Expression<Func<T, bool>> expression ) { return Lambda.GetValue( expression ); } #endregion #region ToLambda(创建Lambda表达式) /// <summary> /// 创建Lambda表达式 /// </summary> /// <typeparam name="TDelegate">委托类型</typeparam> /// <param name="body">表达式</param> /// <param name="parameters">参数列表</param> public static Expression<TDelegate> ToLambda<TDelegate>( this Expression body, params ParameterExpression[] parameters ) { return Expression.Lambda<TDelegate>( body, parameters ); } #endregion }}
在Util项目中添加Operator枚举,代码如下。
using System.ComponentModel;namespace Util { /// <summary> /// 操作符 /// </summary> public enum Operator { /// <summary> /// 等于 /// </summary> [Description( "等于" )] Equal, /// <summary> /// 不等于 /// </summary> [Description( "不等于" )] NotEqual, /// <summary> /// 大于 /// </summary> [Description( "大于" )] Greater, /// <summary> /// 小于 /// </summary> [Description( "小于" )] Less, /// <summary> /// 大于等于 /// </summary> [Description( "大于等于" )] GreaterEqual, /// <summary> /// 小于等于 /// </summary> [Description( "小于等于" )] LessEqual, /// <summary> /// 头尾匹配 /// </summary> [Description( "头尾匹配" )] Contains, /// <summary> /// 头匹配 /// </summary> [Description( "头匹配" )] Starts, /// <summary> /// 尾匹配 /// </summary> [Description( "尾匹配" )] Ends }}
找到Util.Tests测试项目,修改Extensions目录下的ExpressionExtensionTest,代码如下。
using System;using System.Linq.Expressions;using Microsoft.VisualStudio.TestTools.UnitTesting;namespace Util.Tests.Extensions { /// <summary> /// 表达式扩展测试 /// </summary> [TestClass] public class ExpressionExtensionTest { #region 测试初始化 /// <summary> /// 参数表达式 /// </summary> private ParameterExpression _parameterExpression; /// <summary> /// 表达式1 /// </summary> private Expression _expression1; /// <summary> /// 表达式2 /// </summary> private Expression _expression2; /// <summary> /// 测试初始化 /// </summary> [TestInitialize] public void TestInit() { _parameterExpression = Expression.Parameter( typeof( Person ), "t" ); _expression1 = _parameterExpression.Property( "Name" ).Call( "Contains", Expression.Constant( "A" ) ); _expression2 = _parameterExpression.Property( "Birthday" ) .Property( "Value" ) .Property( "Year" ) .Greater( Expression.Constant( 2000 ) ); } #endregion #region And(与操作) /// <summary> /// 测试And方法,连接两个表达式 /// </summary> [TestMethod] public void TestAnd() { var andExpression = _expression1.And( _expression2 ).ToLambda<Func<Person, bool>>( _parameterExpression ); Expression<Func<Person, bool>> expected = t => t.Name.Contains( "A" ) && t.Birthday.Value.Year > 2000; Assert.AreEqual( expected.ToString(), andExpression.ToString() ); } /// <summary> /// 测试And方法,连接两个表达式 /// </summary> [TestMethod] public void TestAnd_2() { Expression<Func<Person, bool>> left = t => t.Name == "A"; Expression<Func<Person, bool>> right = t => t.Name == "B"; Expression<Func<Person, bool>> expected = t => t.Name == "A" && t.Name == "B"; Assert.AreEqual( expected.ToString(), left.And( right ).ToString() ); } #endregion #region Or(或操作) /// <summary> /// 测试Or方法,连接两个表达式 /// </summary> [TestMethod] public void TestOr() { var andExpression = _expression1.Or( _expression2 ).ToLambda<Func<Person, bool>>( _parameterExpression ); Expression<Func<Person, bool>> expected = t => t.Name.Contains( "A" ) || t.Birthday.Value.Year > 2000; Assert.AreEqual( expected.ToString(), andExpression.ToString() ); } /// <summary> /// 测试Or方法,连接两个表达式 /// </summary> [TestMethod] public void TestOr_2() { Expression<Func<Person, bool>> left = t => t.Name == "A"; Expression<Func<Person, bool>> right = t => t.Name == "B"; Expression<Func<Person, bool>> expected = t => t.Name == "A" || t.Name == "B"; Assert.AreEqual( expected.ToString(), left.Or( right ).ToString() ); } #endregion #region Value(获取成员值) /// <summary> /// 获取成员值 /// </summary> [TestMethod] public void TestValue() { Expression<Func<Person, bool>> expression = test => test.Name == "A"; Assert.AreEqual( "A", expression.Value() ); } #endregion #region 运算符操作 /// <summary> /// 测试相等 /// </summary> [TestMethod] public void TestEqual_Nullable() { _expression1 = _parameterExpression.Property( "Age" ).Equal( 1 ); Assert.AreEqual( "t => (t.Age == 1)", _expression1.ToLambda<Func<Person, bool>>( _parameterExpression ).ToString() ); } /// <summary> /// 测试不相等 /// </summary> [TestMethod] public void TestNotEqual_Nullable() { _expression1 = _parameterExpression.Property( "Age" ).NotEqual( 1 ); Assert.AreEqual( "t => (t.Age != 1)", _expression1.ToLambda<Func<Person, bool>>( _parameterExpression ).ToString() ); } /// <summary> /// 测试大于 /// </summary> [TestMethod] public void TestGreater_Nullable() { _expression1 = _parameterExpression.Property( "Age" ).Greater( 1 ); Assert.AreEqual( "t => (t.Age > 1)", _expression1.ToLambda<Func<Person, bool>>( _parameterExpression ).ToString() ); } /// <summary> /// 测试大于等于 /// </summary> [TestMethod] public void TestGreaterEqual_Nullable() { _expression1 = _parameterExpression.Property( "Age" ).GreaterEqual( 1 ); Assert.AreEqual( "t => (t.Age >= 1)", _expression1.ToLambda<Func<Person, bool>>( _parameterExpression ).ToString() ); } /// <summary> /// 测试小于 /// </summary> [TestMethod] public void TestLess_Nullable() { _expression1 = _parameterExpression.Property( "Age" ).Less( 1 ); Assert.AreEqual( "t => (t.Age < 1)", _expression1.ToLambda<Func<Person, bool>>( _parameterExpression ).ToString() ); } /// <summary> /// 测试小于等于 /// </summary> [TestMethod] public void TestLessEqual_Nullable() { _expression1 = _parameterExpression.Property( "Age" ).LessEqual( 1 ); Assert.AreEqual( "t => (t.Age <= 1)", _expression1.ToLambda<Func<Person, bool>>( _parameterExpression ).ToString() ); } #endregion #region Person(测试类) /// <summary> /// 测试 /// </summary> public class Person { public string Name { get; set; } public int? Age { get; set; } public DateTime? Birthday { get; set; } } #endregion }}
需要注意的是,如果需要合并表达式,比如And或Or操作,需要用到一个ParameterRebinder类,它从ExpressionVisitor派生,这个类我是从国外一个网站上直接Copy过来的,代码如下。
using System.Collections.Generic;using System.Linq.Expressions;namespace Util.Lambdas { /// <summary> /// 参数重绑定操作 /// </summary> public class ParameterRebinder : ExpressionVisitor { /// <summary> /// 参数字典 /// </summary> private readonly Dictionary<ParameterExpression, ParameterExpression> _map; /// <summary> /// 初始化参数重绑定操作 /// </summary> /// <param name="map">参数字典</param> public ParameterRebinder( Dictionary<ParameterExpression, ParameterExpression> map ) { _map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); } /// <summary> /// 替换参数 /// </summary> /// <param name="map">参数字典</param> /// <param name="exp">表达式</param> public static Expression ReplaceParameters( Dictionary<ParameterExpression, ParameterExpression> map, Expression exp ) { return new ParameterRebinder( map ).Visit( exp ); } /// <summary> /// 访问参数 /// </summary> /// <param name="parameterExpression">参数</param> protected override Expression VisitParameter( ParameterExpression parameterExpression ) { ParameterExpression replacement; if ( _map.TryGetValue( parameterExpression, out replacement ) ) parameterExpression = replacement; return base.VisitParameter( parameterExpression ); } }}
.Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/xiadao521/
下载地址:http://files.cnblogs.com/xiadao521/Util.2015.1.6.1.rar
Util应用程序框架公共操作类(九):Lambda表达式扩展
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。