Expression<Func<Student, bool>> filter=s=>s.Name.Contains("a") && s.Age>=20;

这样的表达试转换成

Expression<Func<DataRow, bool>> filter = r=>((string)r["Name"]).Contains("a") && ((int)r["Age"])>=20;

也许你会问,干嘛要这样做呢?举个例子,

说DAL里有一个类StudentProvider用于对student进行数据库的增删改查的操作。我们就拿查询来说,查询可以有很多的条件。以往可能会有类似的方法:

public IEnumerable<Student> GetStudentsByName(string name);
public Student GetStudentById(int id);

但是别忘了今天的世界有了Expression,我们应该向这些落后的(别打我,窃以为的)方法说再见了。高颜值的接口当然要写成这样了:

public IEnumerable<Student> GetStudents(Expression<Func<Student, bool>> filter);

于是我们来看看这个方法的实现,

     public IEnumerable<Student> GetStudents(Expression<Func<Student, bool>> filter)
{
using (var connection=new SqlConnection("some connection string"))
{
var selectSql = "SELECT * FROM Student";
using (var adapter = new SqlDataAdapter(selectSql, connection))
{
var ds = new DataSet();
adapter.Fill(ds, "table");
return from raw in ds.Tables["table"].AsEnumerable() select new Student(raw);
}
}
}

实现用到了Linq to DataSet, 其实我们真正想做的是

return from raw in ds.Tables["table"].AsEnumerable().Where(filter) select new Student(raw)

但是问题是Where只接受

Func<DataRow, bool> predicate

到这里,终于明白了为什么要做LambdaExpression变换了吧。

前一篇中我们看到了ExpressionVisitor的强大,这里我们还要用他来解决问题。我们引入一个ConvertMemberToColumnVisitor:

     public class ConvertMemberToColumnVisitor : ExpressionVisitor
{
private readonly Expression _columnOwnerExpression;
private readonly string _memberOwnerName; public ConvertMemberToColumnVisitor(Expression columnOwnerExpression, string memberOwnerName)
{
_columnOwnerExpression = columnOwnerExpression;
_memberOwnerName = memberOwnerName;
} protected override Expression VisitMember(MemberExpression node)
{
var parameterExpression = node.Expression as ParameterExpression;
if (parameterExpression != null && parameterExpression.Name == _memberOwnerName)
{
return Expression.Convert(Expression.Call(_columnOwnerExpression, typeof(DataRow).GetMethod("get_Item", new []{typeof(string)}), Expression.Constant(node.Member.Name)),
((PropertyInfo)node.Member).PropertyType);
} return base.VisitMember(node);
}
}

很简单,很定一个我们要替代成的表达式,当然我们还是用parameter name来匹配所以要给定一个参数名。

有了这个Visitor后,一切问题都简单了:

     public IEnumerable<Student> GetStudents(Expression<Func<Student, bool>> filter)
{
using (var connection=new SqlConnection("some connection string"))
{
var selectSql = "SELECT * FROM Student";
using (var adapter = new SqlDataAdapter(selectSql, connection))
{
var ds = new DataSet();
adapter.Fill(ds, "table"); var p1 = Expression.Parameter(typeof(DataRow), "r");
var converter = new ConvertMemberToColumnVisitor(p1, filter.Parameters[0].Name);
var newExp = converter.Visit(filter);
var lambda = Expression.Lambda<Func<DataRow, bool>>(((LambdaExpression)newExp).Body, p1);
var predicate = lambda.Compile();
return from raw in ds.Tables["table"].AsEnumerable().Where(predicate) select new Student(raw);
}
}
}

Lamda Expression的更多相关文章

  1. Does Lamda expression return value?

    Basically, the compiler does this for you. If you write a lambda as a single statement (and don't in ...

  2. Expression Tree Basics 表达式树原理

    variable point to code variable expression tree data structure lamda expression anonymous function 原 ...

  3. 论C#未来发展

    近日M#的消息令江湖再次起了波澜.大家知道,.NET已经进入了瓶颈期.这个消息又让偶有所期待,趁此机会发表一下个人的展望,对C#或者其继任者,不管是M#还是X#. 一.语法特性 1. using引入类 ...

  4. 数学符号π (Pi)、Σ(Capital Sigma)、μ (Mu) 、σ(sigma)、∏(capital pi), ∫(Integral Symbol)的来历

    1.π (Pi; periphery/周长) March 14 marks Pi Day, the holiday commemorating the mathematical constant π ...

  5. Java learning notes (1):Basic Knowlege points

    Basic Knowlege points: 1: it's necessary that there is only one public class in per .java file 2: .j ...

  6. IMPLEMENTATION - Entity Framework Anti Pattern - High Performance EF

    Good about ORM Developer is free from building T-Sql on the database tier which is not their major a ...

  7. Python 与 Javascript 之比较

    最近由于工作的需要开始开发一些Python的东西,由于之前一直在使用Javascript,所以会不自觉的使用一些Javascript的概念,语法什么的,经常掉到坑里.我觉得对于从Javascript转 ...

  8. Unity在WPF中的应用

    1. 本文的实现类继承于IRepository using System; using System.Linq; using System.Linq.Expressions; using Zhang. ...

  9. [No000012E]WPF(6/7):概念绑定

    WPF 的体系结构,标记扩展,依赖属性,逻辑树/可视化树,布局,转换等.今天,我们将讨论 WPF 最重要的一部分——绑定.WPF 带来了优秀的数据绑定方式,可以让我们绑定数据对象,这样每次对象发生更改 ...

随机推荐

  1. java_基础_类加载

    类加载:Java命令的作用是启动虚拟机,虚拟机通过输入流,从磁盘上将字节码文件(.class文件)中的内容读入虚拟机,并保存起来的过程就是类加载. 类加载特性 :      *在虚拟机的生命周期中一个 ...

  2. 关于Python中迭代器的作用

    迭代器的定义:含有__iter__()方法和__next__()方法的就是迭代器,即(iterate) 含有__iter__()方法就可以使用for循环,即iterable(可迭代的) Iterabl ...

  3. Codeforces 785 - A/B/C/D/E - (Undone)

    链接:https://codeforces.com/contest/785 A - Anton and Polyhedrons #include<bits/stdc++.h> using ...

  4. SQL之NULL值的几种处理方式

    1.创建测试表: drop table if exists tab_null_operator; create table tab_null_operator as select 1 as id,'c ...

  5. 在多个平台如何安装Python

    最近的一个项目,架构师米洛需要用的mqtt,服务器开发的时候,竟然用的python脚本.运行python就需要安装开发环境,好吧,百度一下就知道了大神廖雪峰.以下部分测试通过,转载记录如下. 因为Py ...

  6. [dev][socket] unix domain socket删除socket文件

    问题 在使用unix domain socket的时候,bind之后,会在本地路径里 产生一个与path对应的socket文件. 如何正确的在用完socket之后,对其销毁呢? 方案 使用 unlin ...

  7. sessionStorage 前端HTML5会话管理

    sessionStorage 是在HTML5中新增的一个会话存储对象,sessionStorage 用于临时保存同一窗口(或标签页)的数据,在关闭窗口或标签页之后将会删除这些数据.. 提示: 如果你想 ...

  8. Docker Machine批量安装docker host

    Dokcer Machine Docker Machine 可以批量安装和配置 docker host   提高docker的安装效率   同时减少人工安装操作的失误 [root@localhost ...

  9. mybatis多参数传递(其中包括数组)

    mapper接口 public void batchDelete(@Param(value = "activityId") Integer activityId, @Param(v ...

  10. python 不知道是啥

    1.判断两个大文件是否是同一个文件 import os import hashlib import time start = time.time() path1 = r"E:\视频资料\el ...