建议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. vs2005中microsoft ado data control 6.0控件问题

    在vs2005中是没有这个控件的,需要注册,步骤如下: 1. 先到C:\WINDOWS\system32目录下看看你的系统里是否已经有了MSADODC.ocx和MSDATGRD.ocx这两个文件(多半 ...

  2. rbenv配置

    git clone https://github.com/rbenv/rbenv.git ~/.rbenv # 用来编译安装 ruby git clone git://github.com/sstep ...

  3. php写入、追加写入文件的实例

    $myfile = fopen("newfile.txt", "w") or die("Unable to open file!"); $t ...

  4. MongoDB-WriteConcern

    WriteConcern safe=false 非安全模式 很快

  5. shell 正则表达式与文件名匹配

    1) . : 匹配任意单ASCII 字符,可以为字母,或为数字. 2) 举例: ..XC..匹配deXC1t.23XCdf 等,.w..w..w.匹配rwxrw-rw- 行首以^匹配字符串或字符序列 ...

  6. android httpclient 设置超时

    3.X是这样的 HttpClient httpClient=new DefaultHttpClient();4.3是这样的CloseableHttpClient httpClient = HttpCl ...

  7. telnet WIN7设置回显办法

    windows 2000及XP默认是关闭telnet回显的,这样在操作上很不方便,要让Telnet程序实现本地回显可以按如下步骤操作:1.在命令窗口中运行不带任何参数的telnet命令,执行 /hel ...

  8. 1131 Subway Map

    题意:给出起点和终点,计算求出最短路径(最短路径即所经过的站点最少的),若最短路径不唯一,则选择其中换乘次数最少的一条线路. 思路:本题虽然也是求最短路径,但是此路径是不带权值的,路径长度即所经过的边 ...

  9. php去除html

    代码如下 //清除html function clearhtml($str){ $str = trim($str); $str = strip_tags($str,""); $st ...

  10. Linux性能监测:CPU篇

    CPU 也是一种硬件资源,和任何其他硬件设备一样也需要驱动和管理程序才能使用,我们可以把内核的进程调度看作是 CPU 的管理程序,用来管理和分配 CPU 资源,合理安排进程抢占 CPU,并决定哪个进程 ...