zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    KVM虚拟化学习笔记系列文章列表(转)
    centos 6.5安装docker报错(查看报错详细信息--推荐)
    利用JMX统计远程JAVA进程的CPU和Memory---jVM managerment API
    OpenJDK和JDK区别
    docker sshd image problem, session required pam_loginuid.so, cann't login
    ssh-keygen
    优秀的软件测试人员必需具备的素质
    java基础篇---I/O技术
    jstl long类型数据转换为日期格式
    apache-hadoop-1.2.1、hbase、hive、mahout、nutch、solr安装教程
  • 原文地址:https://www.cnblogs.com/xiadao521/p/4206717.html
Copyright © 2011-2022 走看看