购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

建议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 1;

}

else if(BaseSalary==staff.BaseSalary)

{

return 0;

}

else

{

return-1;

}

//return BaseSalary.CompareTo(staff.BaseSalary);

}

#endregion

}


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

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


ArrayList companySalary=new ArrayList();

companySalary.Add(new Salary(){Name="Mike",BaseSalary=3000});

companySalary.Add(new Salary(){Name="Rose",BaseSalary=2000});

companySalary.Add(new Salary(){Name="Jeffry",BaseSalary=1000});

companySalary.Add(new Salary(){Name="Steve",BaseSalary=4000});

companySalary.Sort();

foreach(Salary item in companySalary)

{

Console.WriteLine(item.Name+"\t BaseSalary:"+item.BaseSalary.ToString());

}


上面代码的输出如下:


Jeffry BaseSalary:1000

Rose BaseSalary:2000

Mike BaseSalary:3000

Steve BaseSalary:4000


现在,问题来了:如果不想以基本工资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=3000,

Bonus=1000});

companySalary.Add(new Salary(){Name="Rose",BaseSalary=2000,

Bonus=4000});

companySalary.Add(new Salary(){Name="Jeffry",BaseSalary=1000,

Bonus=6000});

companySalary.Add(new Salary(){Name="Steve",BaseSalary=4000,

Bonus=3000});

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:3000 Bonus:1000

Name:Steve BaseSalary:4000 Bonus:3000

Name:Rose BaseSalary:2000 Bonus:4000

Name:Jeffry BaseSalary:1000 Bonus:6000


如果我们稍有经验,就会发现上面的代码使用了一个已经不建议使用的集合类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<T>,对应地,我们就该实现IComparable<T>和IComparer<T>。最终的代码应该像下面这样:


static void Main(string[]args)

{

List<Salary>companySalary=new List<Salary>()

{

new Salary(){Name="Mike",BaseSalary=3000,Bonus=1000},

new Salary(){Name="Rose",BaseSalary=2000,Bonus=4000},

new Salary(){Name="Jeffry",BaseSalary=1000,Bonus=6000},

new Salary(){Name="Steve",BaseSalary=4000,Bonus=3000}

};

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));

}

}

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

} EPc11H1nZ3Wj3im+cCGs0zQ1v9D/2in4BmcnBmt+ywDwqCXgsn0OyKAZQATl17wr


点击中间区域
呼出菜单
上一章
目录
下一章
×

打开