Util應用程序框架公共操做類(九):Lambda表達式擴展

  上一篇對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

相關文章
相關標籤/搜索