建议10: 创建对象时需要考虑是否实现比较器
2016-08-30 14:48
323 查看
建议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,对应地,我们就该实现IComparable和IComparer。最终的代码应该像下面这样:
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
}
转自:《编写高质量代码改善C#程序的157个建议》陆敏技
有对象的地方就会存在比较,在.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,对应地,我们就该实现IComparable和IComparer。最终的代码应该像下面这样:
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
}
转自:《编写高质量代码改善C#程序的157个建议》陆敏技
相关文章推荐
- 编写高质量代码改善C#程序的157个建议——建议10: 创建对象时需要考虑是否实现比较器
- Tip10 创建对象时需要考虑是否实现比较器
- close操作前要测试“文件对象”是否创建成功,如果多个流,需要分别去关闭
- new创建一个对象,是否需要加括号?
- 创建的产品对象需要实现 Shape 接口
- new创建一个对象,是否需要加括号?
- c++动态加载dll中的类(用于实现依据字符串类名创建对象)
- .net中实现运行时从字符串动态创建对象
- 使用Regex实现的为JFileChooser使用的FileFilter对象的创建类
- .net中实现运行时从字符串动态创建对象
- Apache - mod_rewrite - RewriteRule中的正则表达式需要考虑是否要对.转义(匹配任意字符还是仅匹配.
- 无法创建 SSIS 运行时对象。请验证 DTS.dll 是否可用及是否已注册。此向导无法继续而将终止。 (SQL
- 创建和销毁对象--考虑用静态工厂方法代替构造函数
- 解决"Automation服务器不能创建对象的"的建议之一
- .net中实现运行时从字符串动态创建对象
- 无法创建DOMDocument对象,请检查是否安装了MS XML Parser 运行库!
- 如何用创建命名对象来判断应用程序是否已有一个实例在运行?
- 实现自定义拖放---创建COleDropSource 对象来控制放置
- 需要License的控件使用示例:创建带License的MSChart对象
- 实现运行时从字符串动态创建对象