Util应用程序框架公共操作类(九):Lambda表达式扩展

时间:2021-09-17 10:15:00

  上一篇对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 = ; i < propertyNameList.Length; i++ ) {
if ( i == ) {
result = Expression.Property( expression, propertyNameList[] );
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 == )
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 == )
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( ) );
} #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 > ;
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 > ;
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( );
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( );
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( );
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( );
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( );
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( );
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表达式扩展的更多相关文章

  1. Util应用程序框架公共操作类&lpar;七&rpar;&colon;Lambda表达式公共操作类

    前一篇扩展了两个常用验证方法,本文将封装两个Lambda表达式操作,用来为下一篇的查询扩展服务. Lambda表达式是一种简洁的匿名函数语法,可以用它将方法作为委托参数传递.在Linq中,大量使用La ...

  2. Util应用程序框架公共操作类&lpar;八&rpar;&colon;Lambda表达式公共操作类&lpar;二&rpar;

    前面介绍了查询的基础扩展,下面准备给大家介绍一些有用的查询封装手法,比如对日期范围查询,数值范围查询的封装等,为了支持这些功能,需要增强公共操作类. Lambda表达式公共操作类,我在前面已经简单介绍 ...

  3. Util应用程序框架公共操作类&lpar;十二&rpar;&colon;Lambda表达式公共操作类&lpar;三&rpar;

    今天在开发一个简单查询时,发现我的Lambda操作类的GetValue方法无法正确获取枚举类型值,以至查询结果错误. 我增加了几个单元测试来捕获错误,代码如下. /// <summary> ...

  4. Util应用程序框架公共操作类

    随笔分类 - Util应用程序框架公共操作类 Util应用程序框架公共操作类 Util应用程序框架公共操作类(五):异常公共操作类 摘要: 任何系统都需要处理错误,本文介绍的异常公共操作类,用于对业务 ...

  5. Util应用程序框架公共操作类&lpar;二&rpar;&colon;数据类型转换公共操作类(源码篇)

    上一篇介绍了数据类型转换的一些情况,可以看出,如果不进行封装,有可能导致比较混乱的代码.本文通过TDD方式把数据类型转换公共操作类开发出来,并提供源码下载. 我们在 应用程序框架实战十一:创建VS解决 ...

  6. Util应用程序框架公共操作类&lpar;六&rpar;&colon;验证扩展

    前面介绍了仓储的基本操作,下面准备开始扩展查询,在扩展查询之前,首先要增加两个公共操作类,一个是经常要用到的验证方法,另一个是Lambda表达式的操作类. 很多时候,我们会判断一个对象是否为null, ...

  7. Util应用程序框架公共操作类&lpar;五&rpar;&colon;异常公共操作类

    任何系统都需要处理错误,本文介绍的异常公共操作类,用于对业务上的错误进行简单支持. 对于刚刚接触.Net的新手,碰到错误的时候,一般喜欢通过返回bool值的方式指示是否执行成功. public boo ...

  8. Util应用程序框架公共操作类&lpar;四&rpar;&colon;验证公共操作类

    为了能够验证领域实体,需要一个验证公共操作类来提供支持.由于我将使用企业库(Enterprise Library)的验证组件来完成这项任务,所以本文也将演示对第三方框架的封装要点. .Net提供了一个 ...

  9. Util应用程序框架公共操作类&lpar;三&rpar;&colon;数据类型转换公共操作类(扩展篇)

    上一篇以TDD方式介绍了数据类型转换公共操作类的开发,并提供了单元测试和实现代码,本文将演示通过扩展方法来增强公共操作类,以便调用时更加简化. 下面以字符串转换为List<Guid>为例进 ...

随机推荐

  1. HTTPS科普扫盲帖

    为什么需要https HTTP是明文传输的,也就意味着,介于发送端.接收端中间的任意节点都可以知道你们传输的内容是什么.这些节点可能是路由器.代理等. 举个最常见的例子,用户登陆.用户输入账号,密码, ...

  2. java计算当前周开始日期&amp&semi;结束日期

    public static Date getFirstDayOfWeek(Date date) { Calendar c = new GregorianCalendar(); c.setFirstDa ...

  3. js替换指定字符串

    // var a = "212"; // var b = []; // for(var i=0;i<a.length;i++){ // if(a[i]=="1&qu ...

  4. 非IE内核浏览器支持activex插件

    之前在一个B/S项目中遇到一个需求,就是客户需要在页面上对报表的布局以及显示内容,进行自定义.最后决定使用activex技术来实现.众所周知,activex是微软搞得,因此只有ie内核的浏览器才能支持 ...

  5. How to fix &OpenCurlyDoubleQuote;Duplicate sources&period;list entry …” issue

    The correct format of repository source line is <type of repository>  <location>  <di ...

  6. jquery 工作空间注册

    在一些面向对象的语言中有命名空间的概念,好处就是把不同的类放在不同的文件夹下面,这样就不会发生命名冲突,当然命名空间还有其他的作用. 在这里我们讨论的是在JS中怎么使用命名空间.当然JS并没有提供原生 ...

  7. jS放大镜效果

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="demo4.aspx.cs& ...

  8. Farming

    Problem Description You have a big farm, and you want to grow vegetables in it. You're too lazy to s ...

  9. ObjectiveC 文件操作一

    1,引用和使用文件 NSFileManager 是一个单例对象,在mac应用中可以获取任何地址,在IOS中获取的是相对应的应用程序的地址.可以使用 defaultManager 来得到当前应用程序地址 ...

  10. php函数参数

    函数的参数 通过参数列表可以传递信息到函数,即以逗号作为分隔符的表达式列表.参数是从左向右求值的. PHP 支持按值传递参数(默认),通过引用传递参数以及默认参数.也支持可变长度参数列表,更多信息参见 ...