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


    建议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 + "	 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} 	BaseSalary:{1} 	Bonus:{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。最终的代码应该像下面这样:

         
        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 = 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} 	BaseSalary:{1} 	Bonus:{2}",  
                    item.Name, item.BaseSalary, item.Bonus));  
            }  
        }  

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

  • 相关阅读:
    python自定义编写有关用户登录注册程序代码
    项目经理多年的经验之谈
    Linux虚拟机克隆后,启动系统发现网卡无法启动
    mysql出现服务器异常后,重启服务器后无法开启数据库处理方法
    计算机毕业四年,我都做了什么?
    个人Blog(采用Django+uwsgi+nginx)里面包含很多技术文章
    Delphi to C# Equivalancesdelphi和C#类似的地方
    Javascript浏览器关于scrollLeft,scrollTop的兼容性
    Mozilla Firefox15怎么样才能把标签页弄到下面去,就和360的一样,Mozilla Firefox15没有取消标签置顶这个选项……
    Delphi过程函数传递参数的几种方式
  • 原文地址:https://www.cnblogs.com/jesselzj/p/4725617.html
Copyright © 2020-2023  润新知