建议10: 创建对象时需要考虑是否实现比较器

有对象的地方就会存在比较,在.NET的世界中也一样。举个最简单的例子,在UI中,有一个10个人的Salary列表。根据排序的需要,列表要支持针对基本工资来罗列Salary。这个时候,接口IComparable就会起作用,代码如下所示:

    class Salary : IComparable
{
public string Name { get; set; }
public int BaseSalary { get; set; }
public int Bonus { get; set; } #region IComparable 成员 public int CompareTo(object obj)
{
Salary staff = obj as Salary;
if (BaseSalary > staff.BaseSalary)
{
return ;
}
else if (BaseSalary == staff.BaseSalary)
{
return ;
}
else
{
return -;
}
//return BaseSalary.CompareTo(staff.BaseSalary);
} #endregion
}

注意 上面代码中CompareTo方法有一条注释的代码,其实本方法完全可以使用该注释代码代替,因为利用了整型的默认比较方法。此处未使用本注释代码,是为了更好地说明比较器的工作原理。

实现了接口IComparable后,我们就可以根据BaseSalary对Salary进行排序了,代码如下所示:

    ArrayList companySalary = new ArrayList();
companySalary.Add(new Salary() { Name = "Mike", BaseSalary = });
companySalary.Add(new Salary() { Name = "Rose", BaseSalary = });
companySalary.Add(new Salary() { Name = "Jeffry", BaseSalary = });
companySalary.Add(new Salary() { Name = "Steve", BaseSalary = });
companySalary.Sort();
foreach (Salary item in companySalary)
{
Console.WriteLine(item.Name + "\t BaseSalary: " + item.BaseSalary.ToString());
}

上面代码的输出如下:

    Jeffry   BaseSalary:
Rose BaseSalary:
Mike BaseSalary:
Steve BaseSalary:

现在,问题来了:如果不想以基本工资BaseSalary进行排序,而是以奖金Bonus进行排序,该如何处理呢?这个时候,接口IComparer的作用就体现出来了,可以使用IComparer来实现一个自定义的比较器。如下所示:

    class BonusComparer : IComparer
{
#region IComparer 成员 public int Compare(object x, object y)
{
Salary s1 = x as Salary;
Salary s2 = y as Salary;
return s1.Bonus.CompareTo(s2.Bonus);
} #endregion
}

我们在排序的时候为Sort方法提供此比较器,代码如下所示:

    ArrayList companySalary = new ArrayList();
companySalary.Add(new Salary() { Name = "Mike", BaseSalary = , Bonus = });
companySalary.Add(new Salary() { Name = "Rose", BaseSalary = , Bonus = });
companySalary.Add(new Salary() { Name = "Jeffry", BaseSalary = , Bonus = });
companySalary.Add(new Salary() { Name = "Steve", BaseSalary = , Bonus = });
companySalary.Sort(new BonusComparer()); //提供一个非默认的比较器
foreach (Salary item in companySalary)
{
Console.WriteLine(string.Format("Name:{0} \tBaseSalary:{1} \tBonus:{2}",
item.Name, item.BaseSalary, item.Bonus));
}

输出结果如下:

    Name:Mike       BaseSalary:         Bonus:
Name:Steve BaseSalary: Bonus:
Name:Rose BaseSalary: Bonus:
Name:Jeffry BaseSalary: Bonus:

如果我们稍有经验,就会发现上面的代码使用了一个已经不建议使用的集合类ArrayList(当泛型出来后,就建议尽量不使用所有非泛型集合类)。至于原因,从上面的代码中我们也可以看出端倪。 注意查看代码中的Compare函数,如:

    public int Compare(object x, object y)
{
Salary s1 = x as Salary;
Salary s2 = y as Salary;
return s1.Bonus.CompareTo(s2.Bonus);
}

我们发现这个函数进行了转型,这是会影响性能的。如果集合中有成千上万个复杂的实体对象,在排序的时候所耗费掉的性能就是可观的;而泛型的出现,可以避免运行时转型。 因此,以上代码中的ArrayList,应该换成List,对应地,我们就该实现IComparable和IComparer。最终的代码应该像下面这样:

    class Salary : IComparable<Salary>
{
public string Name { get; set; }
public int BaseSalary { get; set; }
public int Bonus { get; set; } #region IComparable<Salary> 成员 public int CompareTo(Salary other)
{
return BaseSalary.CompareTo(other.BaseSalary);
} #endregion
} class BonusComparer : IComparer<Salary>
{
#region IComparer<Salary> 成员 public int Compare(Salary x, Salary y)
{
return x.Bonus.CompareTo(y.Bonus);
} #endregion
} static void Main(string[] args)
{
List<Salary> companySalary = new List<Salary>()
{
new Salary() { Name = "Mike", BaseSalary = , Bonus = },
new Salary() { Name = "Rose", BaseSalary = , Bonus = },
new Salary() { Name = "Jeffry", BaseSalary = , Bonus = },
new Salary() { Name = "Steve", BaseSalary = , Bonus = }
};
companySalary.Sort(new BonusComparer()); //提供一个非默认的比较器
foreach (Salary item in companySalary)
{
Console.WriteLine(string.Format("Name:{0} \tBaseSalary:{1} \tBonus:{2}",
item.Name, item.BaseSalary, item.Bonus));
}
}

转自:《编写高质量代码改善C#程序的157个建议》陆敏技

编写高质量代码改善C#程序的157个建议——建议10: 创建对象时需要考虑是否实现比较器的更多相关文章

  1. 编写高质量代码改善C#程序的157个建议[1-3]

    原文:编写高质量代码改善C#程序的157个建议[1-3] 前言 本文主要来学习记录前三个建议. 建议1.正确操作字符串 建议2.使用默认转型方法 建议3.区别对待强制转换与as和is 其中有很多需要理 ...

  2. 读书--编写高质量代码 改善C#程序的157个建议

    最近读了陆敏技写的一本书<<编写高质量代码  改善C#程序的157个建议>>书写的很好.我还看了他的博客http://www.cnblogs.com/luminji . 前面部 ...

  3. 编写高质量代码改善C#程序的157个建议——建议157:从写第一个界面开始,就进行自动化测试

    建议157:从写第一个界面开始,就进行自动化测试 如果说单元测试是白盒测试,那么自动化测试就是黑盒测试.黑盒测试要求捕捉界面上的控件句柄,并对其进行编码,以达到模拟人工操作的目的.具体的自动化测试请学 ...

  4. 编写高质量代码改善C#程序的157个建议——建议156:利用特性为应用程序提供多个版本

    建议156:利用特性为应用程序提供多个版本 基于如下理由,需要为应用程序提供多个版本: 应用程序有体验版和完整功能版. 应用程序在迭代过程中需要屏蔽一些不成熟的功能. 假设我们的应用程序共有两类功能: ...

  5. 编写高质量代码改善C#程序的157个建议——建议155:随生产代码一起提交单元测试代码

    建议155:随生产代码一起提交单元测试代码 首先提出一个问题:我们害怕修改代码吗?是否曾经无数次面对乱糟糟的代码,下决心进行重构,然后在一个月后的某个周一,却收到来自测试版的报告:新的版本,没有之前的 ...

  6. 编写高质量代码改善C#程序的157个建议——建议154:不要过度设计,在敏捷中体会重构的乐趣

    建议154:不要过度设计,在敏捷中体会重构的乐趣 有时候,我们不得不随时更改软件的设计: 如果项目是针对某个大型机构的,不同级别的软件使用者,会提出不同的需求,或者随着关键岗位人员的更替,需求也会随个 ...

  7. 编写高质量代码改善C#程序的157个建议——建议153:若抛出异常,则必须要注释

    建议153:若抛出异常,则必须要注释 有一种必须加注释的场景,即使异常.如果API抛出异常,则必须给出注释.调用者必须通过注释才能知道如何处理那些专有的异常.通常,即便良好的命名也不可能告诉我们方法会 ...

  8. 编写高质量代码改善C#程序的157个建议——建议152:最少,甚至是不要注释

    建议152:最少,甚至是不要注释 以往,我们在代码中不写上几行注释,就会被认为是钟不负责任的态度.现在,这种观点正在改变.试想,如果我们所有的命名全部采用有意义的单词或词组,注释还有多少存在的价值. ...

  9. 编写高质量代码改善C#程序的157个建议——建议151:使用事件访问器替换公开的事件成员变量

    建议151:使用事件访问器替换公开的事件成员变量 事件访问器包含两部分内容:添加访问器和删除访问器.如果涉及公开的事件字段,应该始终使用事件访问器.代码如下所示: class SampleClass ...

  10. 编写高质量代码改善C#程序的157个建议——建议150:使用匿名方法、Lambda表达式代替方法

    建议150:使用匿名方法.Lambda表达式代替方法 方法体如果过小(如小于3行),专门为此定义一个方法就会显得过于繁琐.比如: static void SampeMethod() { List< ...

随机推荐

  1. 异常mongodb:Invalid BSON field name XXXXXX:YYYYY.zz

    1.本周遇到这个问题. 定位到发现一个很神奇的现象上面的结构无法顺利以map的key值存入mongodb里面. 而且到线上才发现这个问题. 而且是部分用户才会出现这样的情况 大部分人的该数据是这样的 ...

  2. spring mvc 返回字符串带双引号及StringHttpMessageConverter乱码处理

    本文转载自:http://blog.csdn.net/wangyangbto/article/details/48804155 很多人都碰到过,SpringMVC使用 @ResponseBody 注解 ...

  3. 【转】 Pro Android学习笔记(九二):AsyncTask(1):AsyncTask类

    文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingflying/ 在Handler的学习系列中,学习了如何h ...

  4. thinkphp实现多个子查询语句

    sql语句博大精深 理解好sql语句,就能用好thinkphp等框架中的数据库操作 原sql SELECT a.*,b.* from (SELECT a.id as opener_id,a.name, ...

  5. python开发进程:进程开启方式&多进程

    一,进程的开启方式 利用模块开启进程 from multiprocessing import Process import time,random import os def piao(name): ...

  6. GitHub in vs2010、vs2013

    GitHub在使用上大致和其他源代码管理工具一样,个人源代码管理和分享一大利器,而且vs2010和vs2013配置也没有任何区别,简单做了一下图文配置说明 一.注册github 1.github.co ...

  7. web deploy 部署网站

    一.服务端配置 1. 确保在服务器端(我目前是win server 2012 R2)安装管理服务 安装后服务器会重启, 2)安装webdeploy http://www.iis.net/downloa ...

  8. Window中的内存地址(小知识)

    现在的编辑器大部分工作都是内存管理托管型,所以很少直接对Window的内存地址直接管理了. Window中的内存地址主要是以16进制数字体现的,当操作系统为32位时,那么每个内存地址为2的32次方,也 ...

  9. Spring Cloud与分布式系统

    本文不是讲解如何使用spring Cloud的教程,而是探讨Spring Cloud是什么,以及它诞生的背景和意义. 背景 2008年以后,国内互联网行业飞速发展,我们对软件系统的需求已经不再是过去” ...

  10. Python3之itertools模块

    Python的内建模块itertools提供了非常有用的用于操作迭代对象的函数. 1.Infinite Iterators Iterator Arguments Results Example cou ...