zoukankan      html  css  js  c++  java
  • C# 常用接口学习 IComparable 和 IComparer

    C# 常用接口学习 IComparable IComparer

    作者:乌龙哈里
    时间:2015-11-01
    平台:Window7 64bit,Visual Studio Community 2015

    参考:

    章节:

    • 接口 IConmparable 实现
    • 接口 IComparable<T> 实现
    • 接口 IComparer<T> 实现

    正文:

    一、接口 IConmparable 的实现

    class Fruit
    {
        public string Name;
        public int Price;
    }

    List<Fruit> fruit = new List<Fruit>();
    fruit.Add(new Fruit { Name = "grape", Price = 30 });
    fruit.Add(new Fruit { Name = "apple", Price = 10 });
    fruit.Add(new Fruit { Name = "banana", Price = 15 });
    fruit.Add(new Fruit { Name = "orage", Price = 12 });

    我们如果想要把水果类按价钱排序,用 Sort() 方法,就需要在 Fruit 类实现 IComparable 接口了。
    去看了net4.0的公开源代码(见参考),只有一个方法:
    int CompareTo(Object obj);
    微软的技术人员在注释里说明了,等于返回0值,大于返回大于0的值,小于返回小于0的值。下面我们按说明来实现这个接口:

    class Fruit : IComparable
    {
        public string Name;
        public int Price;
        public int CompareTo(object obj)
        {
            //实现接口方法一:
            if (obj == null) return 1;
            Fruit otherFruit = obj as Fruit;
            if (Price > otherFruit.Price) { return 1; }
            else
            {
                if (Price == otherFruit.Price) { return 0; }
                else { return -1; }
            }
        }
    }

    测试 Sort() 输出:

    static void Main(string[] args)
    {
        List<Fruit> fruit = new List<Fruit>();
        fruit.Add(new Fruit { Name = "grape", Price = 30 });
        fruit.Add(new Fruit { Name = "apple", Price = 10 });
        fruit.Add(new Fruit { Name = "banana", Price = 15 });
        fruit.Add(new Fruit { Name = "orage", Price = 12 });

        Console.Write("未排序:");
        foreach (var f in fruit) Console.Write($"{f.Name} ");
        Console.WriteLine();

        fruit.Sort();

        Console.Write("排序后:");
        foreach (var f in fruit) Console.Write($"{f.Name} ");
        Console.WriteLine();
        Console.ReadKey();
    }

    //输出结果:
    //未排序:grape apple banana orage
    //排序后:apple orage banana grape

    要是要按照 Name 来排序,只要把 Price 换成 Name就成了。
    我们发现,所有的简单值类型(比如:int ,string 等等)都继承了这个 IComparable 接口的,我们可以借用值类型的 CompareTo() 方法来实现:

    class Fruit : IComparable
    {
        public string Name;
        public int Price;
        public int CompareTo(object obj)
        {
            //实现接口方法二:
            Fruit otherFruit = obj as Fruit;
            return Price.CompareTo(otherFruit.Price);
        }
    }

    对于这个 IComparable 接口,因为基本简单的值类型都有 CompareTo() 方法,而且有了 Linq 后,我只要能用 IEnumerable<T> 的集合类型,用 lambda 表达式很容易就能进行排序 Sort() 操作,而且升序降序排序更加方便。上面的例子中,就算 Fruit 类没有实现 IComparable 接口,我用 List<T>,然后用 lambda 表达式生成一个新的集合就成了,如下:

        class Program
        {
            static void Main(string[] args)
            {
                List<Fruit> fruit = new List<Fruit>();
                fruit.Add(new Fruit { Name = "grape", Price = 30 });
                fruit.Add(new Fruit { Name = "apple", Price = 10 });
                fruit.Add(new Fruit { Name = "banana", Price = 15 });
                fruit.Add(new Fruit { Name = "orage", Price = 12 });

                Console.Write("排序前:");
                foreach (var f in fruit) Console.Write($"{f.Name} ");
                Console.WriteLine();

                var fruitSort = fruit.OrderBy(x => x.Price);

                Console.Write("排序后:");
                foreach (var f in fruitSort) Console.Write($"{f.Name} ");
                Console.WriteLine();

                Console.ReadKey();
            
            }
        }
        class Fruit
        {
            public string Name;
            public int Price;
        }

    真的弄不清楚到底这个接口有了泛型和 Linq 后还有什么用。本着认真学习的态度,我们继续学习它的泛型接口。

    二、接口 IConmparable<T> 的实现

    我们看到在实现 IComparable 中会发生装箱行为:
    Fruit otherFruit=obj as Fruit;
    为了效率就引进了泛型,实现如下:

        class Fruit : IComparable<Fruit>
        {
            public string Name;
            public int Price;
            int IComparable<Fruit>.CompareTo(Fruit other)
            {
                return Price.CompareTo(other.Price);
            }
        }

    调用和普通的一样调用。现在还有个一问题,就是我们在章节一里面所说的,这个 Fruit 类是按字段 Price 来排序的,要是我们想按 Name 来排序,修改 int CompareTo() 方法很不灵活和方便,这时我们就需要另外一个类似的接口 IComparer 来提供便利了。

    三、接口 IConmparer<T> 的实现

    这个 IComparer 我理解为比较器接口,章节一的 Fruit 类接口 IComparable 不改,要想按 Name 来排序,需创立一个新类,在其上实现 IComparer<T> 接口:

        class SortByName : IComparer<Fruit>
        {
            int IComparer<Fruit>.Compare(Fruit x, Fruit y)
            {
                return x.Name.CompareTo(y.Name);
            }
        }
        class Fruit : IComparable
        {
            public string Name;
            public int Price;
            public int CompareTo(object obj)
            {
                //实现接口方法二:
                Fruit otherFruit = obj as Fruit;
                return Price.CompareTo(otherFruit.Price);
            }
        }

    调用: fruit.Sort(new SortByName());
    这个接口给我们带来重大的灵活性和方便性。不过我还是认为在泛型和lambda范式后,这个玩意好像真的没多大用处。

    本文到此结束。

    题外话:C#真的是一门优雅优秀的语言,而且微软开放了部分源代码,值得长期投资。

  • 相关阅读:
    Socket编程实践(6) --TCPNotes服务器
    2014百度之星预赛(第二场)——Best Financing
    操作和维护经常使用的命令
    HDU 5073 Galaxy(Anshan 2014)(数学推导,贪婪)
    [Angular2] @Ngrx/store and @Ngrx/effects learning note
    [AngularJS Ng-redux] Integrate ngRedux
    [AngularFire2] Update multi collections at the same time with FirebaseRef
    [AngularJS] Write a simple Redux store in AngularJS app
    [AngularJS] Using an AngularJS directive to hide the keyboard on submit
    [Javascript] Validate Data with the Every() Method
  • 原文地址:https://www.cnblogs.com/leemano/p/4926637.html
Copyright © 2011-2022 走看看