快速创建 IEqualityComparer 实例:改进
两年前,我写了篇文章《快速创建 IEqualityComparer<T> 和 IComparer<T> 的实例》,文中给出了一个用于快速创建 IEqualityComparer<T> 实例的类 Equality<T>。
在后来的使用中发现了一些不足,在此进行一些改进,以便更好的使用。原文中的 Equality<T> 实现如下:
1 |
public static class Equality<T> |
代码中的问题使用红色粗体标出。
在改进之前,我们需要先弄清两个关于 null 值的两个问题:
关于 null 的两个问题
将定有一个 Person 类:
1 |
public class Peron |
问题一,两个 null 值是否相等?
1 |
Peron p1 = new Peron { Name = null };
|
请告诉我 b1 和 b2 的值。
问题二,为 null 时 HashCode 应该是什么?
1 |
var h1 = StringComparer.InvariantCulture.GetHashCode(p1.Name); |
请告诉我 h1 和 h2 的值。
建议大家想下这两个问题,答案就不给出了,自行调试吧。
你的答案和调试得出的结果可能会有出入,如果这样你得好好思考下了。
Equality<T> 改进后的代码
改进后,代码如下:
1 |
public static class Equality<T> |
以上代码黄色高亮部分为新加入代码。
用法:
1 |
var personNameComparer = Equality<Peron>.CreateComparer(p => p.Name); |
第 28 行代码
此行代码会有很大争议,它会影响 p7 与 p8 比较的结果 b4。
也许有的朋友认为应该将这行代码修改为:
1 |
if(x== null) |
这样得出 b4 的值为 true.
我不赞同这种方式,我的观点是:“p=>p.Name”指定使用 Person 的 Name 进行相等比较,Person若不存在(值为 null), Name 更不存在,也谈不上相等,所以应返回 false。
当然还有另一种想法,Person 不存在,没法比,应该抛出异常。
第 33 行代码
也可以写成:
1 |
return RuntimeHelpers.GetHashCode(null); |
RuntimeHelpers 类在 System.Runtime.CompilerServices 命名空间下,我在反编译 Object 时,在 GetHashCode() 方法中发现了它。
复杂情况下的使用
一位园友问我这样一个问题,如下两个类:
1 |
public class Employee |
要创建 Employee 的相等比较器,根据其学校(School)的所在城市(City)。不考虑一个 Employee 多个 School 的情况,但要考虑 Employee 的 School 属性为 null 的情况(可能没上过学)。
用以下方式创建:
1 |
var employeeComparer = Equality<Employee>.CreateComparer(i => i.School.City); |
运行时,可能会出错。执行比较时,遇到 Employee 的 School 属性为 null ,便会抛出 NullReferenceException。
一种可行的写法是:
1 |
var companylComparer = Equality<School>.CreateComparer(i => i.City); |
是的,分两步。也许是麻烦了些,不过试想下如果没有 Equality<T> 类的帮助,如果实现这个这个相等比较器?相当麻烦,不信可以试着写下。
简单测试下:
1 |
var v0 = new Employee { School = new School { City = "Beijing" } };
|
再搞复杂一点
把前面的 City 变成一个类,代码如下:
1 |
public class Employee |
还是要求创建 Employee 的相等比较器,根据 Employee 的 School 的 City 的 Country 来判断。要考虑各引用属性的为 null 时的情形。
还不过瘾,就再加点难度! Country 比较时不考虑大小写。
嘻嘻,有谁能告诉我如何创建,可以使用本文中的 Equality<T>,也可以不用。当然,越简洁越好。
知道的话,请回复我,非常期待你的参与!
后记
终于赶在最后一分钟完成了2013年最后一篇文章。三更半夜,行文仓促,如有疏漏,请多包涵。
祝大家 2014 年新年快乐!有更大的收获!
快速创建 IEqualityComparer 实例:改进的更多相关文章
- 于快速创建 IEqualityComparer<T> 实例的类 Equality<T>
于快速创建 IEqualityComparer<T> 实例的类 Equality<T> 原文中的 Equality<T> 实现如下: 1 2 3 4 5 6 7 8 ...
- Hype-v创建服务器实例
1.创建虚拟交换机,如下图所示(虚拟交换机,只需要创建一次,后面增加服务器实例的时候,只需要选择这个虚拟交换机就可以了,不用每次都创建) 2.服务器主网络共享给虚拟交换机,如下图所 3.虚拟交换机的I ...
- 一分钟在云端快速创建MySQL数据库实例
本教程将帮助您了解如何使用Azure管理门户迅速创建,连接,配置MySQL 数据库 on Azure.完成本教程后,您将在Azure上拥有一个示例MySQL数据库服务器,并了解如何使用管理门户执行基本 ...
- 单机静默安装GI软件并创建ASM实例和ASM磁盘组
环境:RHEL 6.4 + Oracle 11.2.0.4 需求:单机静默安装GI软件并创建ASM实例和ASM磁盘组,为后续迁移数据库文件到ASM做准备 1. 安装配置GI软件 2. 创建ASM实例 ...
- (视频)《快速创建网站》 4.2 完结篇 – 应用运营vs.发射卫星,遥测(Telemetry) 技术
本文是<快速创建网站>系列的第10篇(完结篇),如果你还没有看过之前的内容,建议你点击以下目录中的章节先阅读其他内容再回到本文.访问本系列目录,请点击:http://devopshub.c ...
- (视频) 《快速创建网站》3.4 网站改版3分钟搞定 - WordPress主题安装和备份
本文是<快速创建网站>系列的第8篇,如果你还没有看过之前的内容,建议你点击以下目录中的章节先阅读其他内容再回到本文. 访问本系列目录,请点击:http://devopshub.cn/tag ...
- (视频) 《快速创建网站》 2.3 WordPress初始化和功能简介
本文是<快速创建网站>系列的第4篇,如果你还没有看过之前的内容,建议你点击以下目录中的章节先阅读其他内容再回到本文. 访问本系列目录,请点击:http://devopshub.cn/tag ...
- (视频) 《快速创建网站》2.1 在Azure上创建网站及网站运行机制
现在让我们开始一天的建站之旅. 本文是<快速创建网站>系列的第2篇,如果你还没有看过之前的内容,建议你点击以下目录中的章节先阅读其他内容再回到本文. 访问本系列目录,请点击:http:// ...
- (视频) 《快速创建网站》1. 网站管理平台WordPress & 微软Azure 云计算简介
网站并不神秘,过节了,在家闲的没事的,自己建个网站玩玩吧.每段视频不超过15分钟,地铁/公交/睡前/醒来看一段,几天之后变身建站专家,找老板加薪去! 在普通人眼里,创建网站是专业开发人员和IT工程师才 ...
随机推荐
- jQuery动画特效实例教程
本文以实例形式详细讲述了jQuery动画特效的实现方法. 1.自制折叠内容块 内容块如下: <div class="module"> <div cla ...
- Android 自定义线程池的实战
前言:在上一篇文章中我们讲到了AsyncTask的基本使用.AsyncTask的封装.AsyncTask 的串行/并行线程队列.自定义线程池.线程池的快速创建方式. 对线程池不了解的同学可以先看 An ...
- ios textfield / textview长按复制粘贴中文显示
当我们在写应用时要复制粘贴文本框内容时,默认显示的文字为英文字体,可按如下步骤设置,显示中文:
- MySQL 的相关语句(增删改查)(SQLyog软件实现)
-- 创建雇员表:emp CREATE TABLE emp( empno INT, -- 员工编号 ename ), -- 员工姓名 job ), -- 员工工作 mgr INT, -- 领导编号 h ...
- Ajax.ActionLink参数详解
该语法会生成一个a标签,点击a标签会执行一个Ajax请求. 有12个方法重载,下面详解方法中的各项参数: 参数一:linkText string类型 说明:链接显示的文字内容 参数二:actionNa ...
- Nagios学习实践系列——产品介绍篇
Nagios介绍 Nagios是一款功能强大.优秀的开源监控系统,它能够让你发现和解决IT架构中存在的问题,避免这些问题影响到关键业务流程. Nagios最早于1999年发布,它在开源社区的影响力是相 ...
- 浅析SQL SERVER执行计划中的各类怪相
在查看执行计划或调优过程中,执行计划里面有些现象总会让人有些疑惑不解: 1:为什么同一条SQL语句有时候会走索引查找,有时候SQL脚本又不走索引查找,反而走全表扫描? 2:同一条SQL语句,查询条件的 ...
- jQuery标签选择器
$(function() { //alert("hello jquery"); //选择器 //id选择器 $("#bt1").click( function( ...
- Linux 多线程可重入函数
Reentrant和Thread-safe 在单线程程序中,整个程序都是顺序执行的,一个函数在同一时刻只能被一个函数调用,但在多线程中,由于并发性,一个函数可能同时被多个函数调用,此时这个函数就成了临 ...
- 自动创建WIN32下多级子目录的C++封装类
这是 WIN32 自动创建多级子目录的 C++ 封装类,用法简单. 封装没有采用类的静态函数方式,而是在构造函数里面直接完成工作.没什么具体的原因,只是当时做成这样了, ...