上一篇對Lambda表達式公共操做類進行了一些加強,本篇使用擴展方法對Lambda表達式進行擴展。express
修改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枚舉,代碼以下。ide
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,歡迎有興趣的朋友加入討論。this
謝謝你們的持續關注,個人博客地址:http://www.cnblogs.com/xiadao521/spa
下載地址:http://files.cnblogs.com/xiadao521/Util.2015.1.6.1.rarcode