趣味编程:C#中Specification模式的实现(参考答案

上一篇文章中我们利用C#语言的特性实现了一种轻量级的Specification模式,它的关键在于抛弃了具体的Specification类型,而是使用一个委托对象代替唯一关键的IsSatisfiedBy方法逻辑。据我们分析,其优势之一在于使用简单,其劣势之一在于无法静态表示。但是它们还都是在处理“业务逻辑”,如果涉及到一个用于LINQ查询或其他地方的表达式树,则问题就不那么简单了——但也没有我们想象的那么复杂。

好,那么我们就把场景假想至LINQ上。LINQ与普通业务逻辑不同的地方在于,它不是用一个IsSatisfiedBy方法或一个委托对象用来表示判断逻辑,而是需要构造一个表达式树,一种数据结构。如果您还不清楚表达式树是什么,那么可以看一下脑袋的写的上手指南。这是.NET 3.5带来的重要概念,在4.0中又得到了重要发展,如果您要在.NET方面前进,这是一条必经之路。

And、Or和Not之间,最容易处理的便是Not方法,于是我们从这个地方下手,直接来看它的实现:

public static class SpecExprExtensions
{
  public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> one)
  {
    var candidateExpr = one.Parameters[0];
    var body = Expression.Not(one.Body);

    return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
  }
}

一个Expression<TDelegate>对象中主要有两部分内容,一是参数,二是表达式体(Body)。对于Not方法来说,我们只要获取它的参数表达式,再将它的Body外包一个Not表达式,便可以此构造一个新的表达式了。这部分逻辑非常简单,看了脑袋的文章,了解了表达式树的基本结构就能理解这里的含义。那么试验一下:

Expression<Func<int, bool>> f = i => i % 2 == 0;
f = f.Not();

foreach (var i in new int[] { 1, 2, 3, 4, 5, 6 }.AsQueryable().Where(f))
{
  Console.WriteLine(i);
}

打印出来的自然是所有的奇数,即1、3、5。

而And和Or的处理上会有所麻烦,我们不能这样像Not一样简单处理:

public static Expression<Func<T, bool>> And<T>(
  this Expression<Func<T, bool>> one, Expression<Func<T, bool>> another)
{
  var candidateExpr = one.Parameters[0];
  var body = Expression.And(one.Body, another.Body);
  return Expression.Lambda<Func<T, bool>>(body, candidateExpr);
}

这么做虽然能够编译通过,但是在执行时便会出错。原因在于one和another两个表达式虽然都是同样的形式(Expression<Func<T, bool>>),但是它们的“参数”不是同一个对象。也就是说,one.Body和another.Body并没有公用一个 ParameterExpression实例,于是我们无论采用哪个表达式的参数,在Expression.Lambda方法调用的时候,都会告诉您新的 body中的某个参数对象并没有出现在参数列表中。

于是,我们如果要实现And和Or,做的第一件事情便是统一两个表达式树的参数,于是我们准备一个ExpressionVisitor:

internal class ParameterReplacer : ExpressionVisitor
{
  public ParameterReplacer(ParameterExpression paramExpr)
  {
    this.ParameterExpression = paramExpr;
  }

  public ParameterExpression ParameterExpression { get; private set; }

  public Expression Replace(Expression expr)
  {
    return this.Visit(expr);
  }

  protected override Expression VisitParameter(ParameterExpression p)
  {
    return this.ParameterExpression;
  }
}

时间: 2024-12-04 17:10:41

趣味编程:C#中Specification模式的实现(参考答案的相关文章

趣味编程:将事件视为对象(参考答案)

这次我们是要编写一个DelegateEvent<TDelegate>对象,提供它AddHandler和RemoveHandler的实现.事实上,在之前还有一篇文章中,我们搞了一个人模狗样的构造方式,但是它往往不适合用于实际使用过程中.因此,其实DelegateEvent<TDelegate>最关键的地方还是各种不同的"构造方式",使它可以用于各种情况. 方法一:直接提供添加删除的实现 在之前的文章里,已经有一些朋友提出了最简单的做法,即直接提供AddHandle

趣味编程:C#中Specification模式的实现

今天有朋友在问了我这么一个问题:怎么实现OrWhere的功能?我猜测,他的意思是要实现这样的功能: static IEnumerable<int> MorePredicate(IEnumerable<int> source) { return source.OrWhere(i => i > 0); // 或所有的正数 } static void Main(string[] args) { var array = Enumerable.Range(-5, 10).ToAr

c++-C++ 基础趣味编程 字母频率

问题描述 C++ 基础趣味编程 字母频率 自行在网上下载英文文章,要求字母个数在1万以上,如果不到1万,请下载多篇合并,命名为data.txt. 对于data.txt,完成以下作业: (1)统计26个字母出现的频率(出现次数在所有字母个数中占的百分比),并排序. (2)输入一个字母,找出和它最亲密的三个字母(最亲密的意思是:和它一起相邻出现的次数最多). (3)找出出现频率最高的五个单词并排序. (4)将前3个题目中的结果以合理的形式输出到文件result.txt. 解决方案 要详细代码,请采纳

云计算编程模型中 Java 应用刍议

云计算编程模型中 Java 应用刍议 艾昊 云计算是基于互联网的新型计算模式,其能提供的服务类别包括 SaaS.PaaS.IaaS,并且各种应用均有 PAAS 负责管理.本文对能够支持 Java 云应用的 PAAS进行分析,并在此基础上探讨了Java在云计算编程模型中的应用,以期为云计算的发展提供参考. 云计算编程模型中 Java 应用刍议

Java 编程技术中汉字问题的分析及解决(转)

编程|汉字|解决|问题 Java 编程技术中汉字问题的分析及解决 段明辉自由撰稿人2000 年 11月 8日内容: 汉字编码的常识 Java 中文问题的初步认识 Java 中文问题的表层分析及处理 Java 中文问题的根源分析及解决 Java Servlet 中文问题的根源 修改 Servlet.jar 中文乱码的处理函数 参考资料 作者简介在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题.一大堆看不懂的乱码肯定不是我们愿意看到的显示效果,怎样才能够让那些汉字正确显示呢?Jav

Java 编程技术中汉字问题的分析及解决,文件操作

编程|汉字|解决|问题 在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题.一大堆看不懂的 乱码肯定不是我们愿意看到的显示效果,怎样才能够让那些汉字正确显示呢?Java 语言 默认的编码方式是UNICODE ,而我们中国人通常使用的文件和数据库都是基于 GB2312 或者 BIG5 等方式编码的,怎样才能够恰当地选择汉字编码方式并正确地处理汉字的编 码呢?本文将从汉字编码的常识入手,结合 Java 编程实例,分析以上两个问题并提出 解决它们的方案. 现在 Java 编程语言已经广

Java 编程技术中汉字问题的分析及解决(转自IBM)

编程|汉字|解决|问题 Java 编程技术中汉字问题的分析及解决 段明辉自由撰稿人2000 年 11月 8日 在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题.一大堆看不懂的乱码肯定不是我们愿意看到的显示效果,怎样才能够让那些汉字正确显示呢?Java 语言默认的编码方式是UNICODE ,而我们中国人通常使用的文件和数据库都是基于 GB2312 或者 BIG5 等方式编码的,怎样才能够恰当地选择汉字编码方式并正确地处理汉字的编码呢?本文将从汉字编码的常识入手,结合 Java 编

Java 编程技术中汉字问题的分析及解决

编程|汉字|解决|问题 在基于 Java 语言的编程中,我们经常碰到汉字的处理及显示的问题.一大堆看不懂的乱码肯定不是我们愿意看到的显示效果,怎样才能够让那些汉字正确显示呢?Java 语言默认的编码方式是UNICODE ,而我们中国人通常使用的文件和数据库都是基于 GB2312 或者 BIG5 等方式编码的,怎样才能够恰当地选择汉字编码方式并正确地处理汉字的编码呢?本文将从汉字编码的常识入手,结合 Java 编程实例,分析以上两个问题并提出解决它们的方案. 现在 Java 编程语言已经广泛应用于

小结:PHP编程过程中应当注意的各种注意事项

最近一段时间,PHP凭借其功能强大,简单易用的特点被越来越多的人们所喜爱和接受,成为目前最为流行的脚本编程语言之一.本文将结合用户在使用PHP过程中经常容易出现的问题,包括语法错误,程序运行错误以及逻辑错误等展开详细的介绍,希望能够对那些目前正在学习PHP语言的用户有所帮助.此外,本文还将会在文章的结束部分对PHP编程过程中应当注意的各种事项加以汇总,供读者参考. PHP脚本语言所具有一个显著的特点就是能够自动生成变量实例,不要求用户对所需要使用的变量进行声明.该特点既有值得推崇之处,但是同时也