Util应用程序框架公共操作类(七):Lambda表达式公共操作类
前一篇扩展了两个常用验证方法,本文将封装两个Lambda表达式操作,用来为下一篇的查询扩展服务。
Lambda表达式是一种简洁的匿名函数语法,可以用它将方法作为委托参数传递。在Linq中,大量使用Lambda表达式进行查询,不过这种Lambda表达式被Expression包装成表达式树。表达式树是解释器的一个实现,它的作用是将一种语法转换为另一种语法,比如将Lambda表达式解析为Sql语句。
使用Sql列名进行查询的主要问题是,列名是一个字符串,没有智能提示,如果输入错误,也没有编译时检查。使用Lambda表达式查询可以解决这些问题,这是使用强类型的主要好处,另外当列名与属性名不一致时,只需修改映射配置,业务代码不动,从而增强了系统的扩展性。
Lambda表达式的强类型在带来诸多好处的同时,也产生了一些问题,比如t => t.Name==”a”这个表达式,如果想把值”a”拿出来进行操作,怎么做到?值”a”对于查询条件来讲,是一个动态传入的参数,如果对表达式树完全不了解,这也不是一件轻松的事。另外还有动态查询的问题,这时候开始怀念弱类型的字符串了,微软提供了一个动态查询的辅助类来解决这个问题,待用到的时候我再介绍。
本文介绍的一个方法是GetValue,用来将Lambda谓词表达式中的值取出来,另一个方法是GetCriteriaCount,用来判断Lambda谓词表达式中条件的个数。这两个方法的具体应用将在下一篇介绍。
在Util项目中添加一个Lambda类,代码如下。
using System.Linq;
using System.Linq.Expressions; namespace Util {
/// <summary>
/// Lambda表达式操作
/// </summary>
public class Lambda { #region GetValue(获取值) /// <summary>
/// 获取值,范例:t => t.Name == "A",返回 A
/// </summary>
/// <param name="expression">表达式,范例:t => t.Name == "A"</param>
public static object GetValue( LambdaExpression expression ) {
if ( expression == null )
return null;
BinaryExpression binaryExpression = GetBinaryExpression( expression );
if ( binaryExpression != null )
return GetBinaryValue( binaryExpression );
var callExpression = expression.Body as MethodCallExpression;
if ( callExpression != null )
return GetMethodValue( callExpression );
return null;
} /// <summary>
/// 获取二元表达式
/// </summary>
private static BinaryExpression GetBinaryExpression( LambdaExpression expression ) {
var binaryExpression = expression.Body as BinaryExpression;
if ( binaryExpression != null )
return binaryExpression;
var unaryExpression = expression.Body as UnaryExpression;
if ( unaryExpression == null )
return null;
return unaryExpression.Operand as BinaryExpression;
} /// <summary>
/// 获取二元表达式的值
/// </summary>
private static object GetBinaryValue( BinaryExpression binaryExpression ) {
var unaryExpression = binaryExpression.Right as UnaryExpression;
if ( unaryExpression != null )
return GetConstantValue( unaryExpression.Operand );
return GetConstantValue( binaryExpression.Right );
} /// <summary>
/// 获取常量值
/// </summary>
private static object GetConstantValue( Expression expression ) {
var constantExpression = expression as ConstantExpression;
if ( constantExpression == null )
return null;
return constantExpression.Value;
} /// <summary>
/// 获取方法调用表达式的值
/// </summary>
private static object GetMethodValue( MethodCallExpression callExpression ) {
var argumentExpression = callExpression.Arguments.FirstOrDefault();
return GetConstantValue( argumentExpression );
} #endregion #region GetCriteriaCount(获取谓词条件的个数) /// <summary>
/// 获取谓词条件的个数
/// </summary>
/// <param name="expression">谓词表达式,范例:t => t.Name == "A"</param>
public static int GetCriteriaCount( LambdaExpression expression ) {
if ( expression == null )
return ;
var result = expression.ToString().Replace( "AndAlso", "|" ).Replace( "OrElse", "|" );
return result.Split( '|' ).Count();
} #endregion
}
}
为了进行测试,需要创建一个测试样例类Test,代码如下。
namespace Util.Tests.Samples {
/// <summary>
/// 测试
/// </summary>
public class Test {
public string Name { get; set; }
public int Age { get; set; }
public int? NullableInt { get; set; }
public decimal? NullableDecimal { get; set; }
public TestA A { get; set; }
public class TestA {
public int Integer { get; set; }
public string Address { get; set; }
public TestB B { get; set; }
public class TestB {
public string Name { get; set; }
}
}
}
}
单元测试代码如下。
using System;
using System.Linq.Expressions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Util.Tests.Samples; namespace Util.Tests {
/// <summary>
/// Lambda表达式操作测试
/// </summary>
[TestClass]
public class LambdaTest { #region GetValue(获取成员值) /// <summary>
/// 获取成员值,委托返回类型为Object
/// </summary>
[TestMethod]
public void TestGetValue_Object() {
Expression<Func<Test, object>> expression = test => test.Name == "A";
Assert.AreEqual( "A", Lambda.GetValue( expression ) );
} /// <summary>
/// 获取成员值,委托返回类型为bool
/// </summary>
[TestMethod]
public void TestGetValue_Boolean() {
//空值返回null
Assert.AreEqual( null, Lambda.GetValue( null ) ); //一级返回值
Expression<Func<Test, bool>> expression = test => test.Name == "A";
Assert.AreEqual( "A", Lambda.GetValue( expression ) ); //二级返回值
Expression<Func<Test, bool>> expression2 = test => test.A.Integer == ;
Assert.AreEqual( , Lambda.GetValue( expression2 ) ); //三级返回值
Expression<Func<Test, bool>> expression3 = test => test.A.B.Name == "B";
Assert.AreEqual( "B", Lambda.GetValue( expression3 ) );
} /// <summary>
/// 获取可空类型的值
/// </summary>
[TestMethod]
public void TestGetValue_Nullable() {
//可空整型
Expression<Func<Test, bool>> expression = test => test.NullableInt == ;
Assert.AreEqual( , Lambda.GetValue( expression ) ); //可空decimal
expression = test => test.NullableDecimal == 1.5M;
Assert.AreEqual( 1.5M, Lambda.GetValue( expression ) );
} /// <summary>
/// 获取成员值,运算符为方法
/// </summary>
[TestMethod]
public void TestGetValue_Method() {
//1级返回值
Expression<Func<Test, bool>> expression = t => t.Name.Contains( "A" );
Assert.AreEqual( "A", Lambda.GetValue( expression ) ); //二级返回值
expression = t => t.A.Address.Contains( "B" );
Assert.AreEqual( "B", Lambda.GetValue( expression ) ); //三级返回值
expression = t => t.A.B.Name.StartsWith( "C" );
Assert.AreEqual( "C", Lambda.GetValue( expression ) );
} #endregion #region GetCriteriaCount(获取谓词条件的个数) /// <summary>
/// 获取谓词条件的个数
/// </summary>
[TestMethod]
public void TestGetCriteriaCount() {
//0个条件
Assert.AreEqual( , Lambda.GetCriteriaCount( null ) ); //1个条件
Expression<Func<Test, bool>> expression = test => test.Name == "A";
Assert.AreEqual( , Lambda.GetCriteriaCount( expression ) ); //2个条件,与连接符
expression = test => test.Name == "A" && test.Name == "B";
Assert.AreEqual( , Lambda.GetCriteriaCount( expression ) ); //2个条件,或连接符
expression = test => test.Name == "A" || test.Name == "B";
Assert.AreEqual( , Lambda.GetCriteriaCount( expression ) ); //3个条件
expression = test => test.Name == "A" && test.Name == "B" || test.Name == "C";
Assert.AreEqual( , Lambda.GetCriteriaCount( expression ) ); //3个条件,包括导航属性
expression = test => test.A.Address == "A" && test.Name == "B" || test.Name == "C";
Assert.AreEqual( , Lambda.GetCriteriaCount( expression ) );
} /// <summary>
/// 获取谓词条件的个数,运算符为方法
/// </summary>
[TestMethod]
public void TestGetCriteriaCount_Method() {
//1个条件
Expression<Func<Test, bool>> expression = t => t.Name.Contains( "A" );
Assert.AreEqual( , Lambda.GetCriteriaCount( expression ) ); //2个条件,与连接
expression = t => t.Name.Contains( "A" ) && t.Name == "A";
Assert.AreEqual( , Lambda.GetCriteriaCount( expression ) ); //2个条件,或连接,包含导航属性
expression = t => t.Name.Contains( "A" ) || t.A.Address == "A";
Assert.AreEqual( , Lambda.GetCriteriaCount( expression ) );
} #endregion
}
}
需要注意的是,GetValue方法不仅要能获取t=>t.Name==”a”这样的二元表达式,还要能获取方法调用表达式中的值,比如t=>t.Name.Contains(“a”)。
下面再增加一个扩展方法,在Util项目中添加名为Extensions.Expression的文件,代码如下。
using System;
using System.Linq.Expressions; namespace Util {
/// <summary>
/// 表达式扩展
/// </summary>
public static partial class Extensions { #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
}
}
Lambda表达式不仅在查询上大展身手,而且在表现层,比如Mvc上也有大量的应用。本文只介绍下一篇基础查询扩展需要用到的两个方法,其它方法我会在需要用到的时候补充进来。
.Net应用程序框架交流QQ群: 386092459,欢迎有兴趣的朋友加入讨论。
谢谢大家的持续关注,我的博客地址:http://www.cnblogs.com/xiadao521/
如果需要下载代码,请参考Util应用程序框架公共操作类(六):验证扩展
Util应用程序框架公共操作类(七):Lambda表达式公共操作类的更多相关文章
- Util应用程序框架公共操作类(八):Lambda表达式公共操作类(二)
前面介绍了查询的基础扩展,下面准备给大家介绍一些有用的查询封装手法,比如对日期范围查询,数值范围查询的封装等,为了支持这些功能,需要增强公共操作类. Lambda表达式公共操作类,我在前面已经简单介绍 ...
- Util应用程序框架公共操作类(十二):Lambda表达式公共操作类(三)
今天在开发一个简单查询时,发现我的Lambda操作类的GetValue方法无法正确获取枚举类型值,以至查询结果错误. 我增加了几个单元测试来捕获错误,代码如下. /// <summary> ...
- Util应用程序框架公共操作类(九):Lambda表达式扩展
上一篇对Lambda表达式公共操作类进行了一些增强,本篇使用扩展方法对Lambda表达式进行扩展. 修改Util项目的Extensions.Expression.cs文件,代码如下. using Sy ...
- Util应用程序框架公共操作类(六):验证扩展
前面介绍了仓储的基本操作,下面准备开始扩展查询,在扩展查询之前,首先要增加两个公共操作类,一个是经常要用到的验证方法,另一个是Lambda表达式的操作类. 很多时候,我们会判断一个对象是否为null, ...
- Util应用程序框架公共操作类(四):验证公共操作类
为了能够验证领域实体,需要一个验证公共操作类来提供支持.由于我将使用企业库(Enterprise Library)的验证组件来完成这项任务,所以本文也将演示对第三方框架的封装要点. .Net提供了一个 ...
- Util应用程序框架公共操作类
随笔分类 - Util应用程序框架公共操作类 Util应用程序框架公共操作类 Util应用程序框架公共操作类(五):异常公共操作类 摘要: 任何系统都需要处理错误,本文介绍的异常公共操作类,用于对业务 ...
- Effective Java 第三版——42.lambda表达式优于匿名类
Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...
- Java 终于有 Lambda 表达式啦~Java 8 语言变化——Lambda 表达式和接口类更改【转载】
原文地址 en cn 下载 Demo Java™ 8 包含一些重要的新的语言功能,为您提供了构建程序的更简单方式.Lambda 表达式 为内联代码块定义一种新语法,其灵活性与匿名内部类一样,但样板文件 ...
- 全新升级的AOP框架Dora.Interception[4]: 基于Lambda表达式的拦截器注册方式
如果拦截器应用的目标类型是由自己定义的,Dora.Interception(github地址,觉得不错不妨给一颗星)可以在其类型或成员上标注InterceptorAttribute特性来应用对应的拦截 ...
随机推荐
- nfs配置注意点
#ip与括号之间不能有空格,不加rw参数时挂载的目录是只读的 /eqp/export/ 10.10.30.0/24(rw,sync,no_root_squash) #更改目录所属的组和所属的用户(nf ...
- MUI框架---实现百度地图定位功能
1 2 <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak= ...
- 四则运算安卓客户端UI截图(部分)
1.我们组安卓手机客户端UI设计主要由林培文同学负责,界面中用到的素材全部由他一人用PS制作,所以在素材来源上当属原创啦.正因为UI由一个人设计,同时他还得分担少量后台代码的编写,颇多的工作量与人才短 ...
- SQL Server 2016五大优势挖掘企业用户数据价值
SQL Server 2016五大优势挖掘企业用户数据价值 转载自:http://soft.zdnet.com.cn/software_zone/2016/0318/3074442.shtml 3月1 ...
- Android安全开发之安全使用HTTPS
Android安全开发之安全使用HTTPS 1.HTTPS简介 阿里聚安全的应用漏洞扫描器中有证书弱校验.主机名弱校验.webview未校验证书的检测项,这些检测项是针对APP采用HTTPS通信时容易 ...
- js问题杂记
1.如何把字符串数组 转成数组对象? eval妙用 var str = "[\"UserName=1,Pwd=1\",\"UserNmae=1,Pwd=1,Sa ...
- 写一个脚本,自动启动tomcat
我的服务器是使用tomcat的,时不时tomcat的进程会突然结束掉,不知道为什么,从日志上看也没有任何可疑之处,貌似就这样突然没了,接下来的日志都是重新启动tomcat之后打印的了.原因找不到,但要 ...
- 编译Android AOSP代码
下载完了源代码,终于到了编译的阶段了.这个阶段远比你想象的简单,一个make命令就可以完成源代码的编译了.参照下面的教程你就可以编译出适用于Android源代码树上的所有分支,包括master.基本的 ...
- MapReduce剖析笔记之二:Job提交的过程
上一节以WordCount分析了MapReduce的基本执行流程,但并没有从框架上进行分析,这一部分工作在后续慢慢补充.这一节,先剖析一下作业提交过程. 在分析之前,我们先进行一下粗略的思考,如果要我 ...
- 跟vczh看实例学编译原理——二:实现Tinymoe的词法分析
文章中引用的代码均来自https://github.com/vczh/tinymoe. 实现Tinymoe的第一步自然是一个词法分析器.词法分析其所作的事情很简单,就是把一份代码分割成若干个tok ...