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#真的是一门优雅优秀的语言,而且微软开放了部分源代码,值得长期投资。

C# 常用接口学习 IComparable 和 IComparer的更多相关文章

  1. C# 常用接口学习 ICollection<T>

    C# 常用接口学习 ICollection<T> 作者:乌龙哈里 时间:2015-11-01 平台:Window7 64bit,Visual Studio Community 2015 参 ...

  2. C# 常用接口学习 IEnumerable<T>

    作者:乌龙哈里 时间:2015-10-24 平台:Window7 64bit,Visual Studio Community 2015 本文参考: MSDN IEnumerable<T> ...

  3. 常用接口简析2---IComparable和IComparer接口的简析

    常用接口的解析(链接) 1.IEnumerable深入解析 2.IEnumerable.IEnumerator接口解析 3.IList.IList接口解析 默认情况下,对象的Equals(object ...

  4. 数组自定义排序:IComparable和IComparer接口

    首先先说一下IComparable和IComparer的区别,前者必须在实体类中实现,后者可以单独出现在一个排序类中,即此类只包含一个compare方法. Array类使用快速算法对数组中的元素进行排 ...

  5. [0] 关于IComparable和IComparer接口和Comparer类

    关于IComparable和IComparer接口 和 Comparer类 IComparable和ICompareframeworkr接口是.net 中比较对象的标准方式,这两个接口之间的区别如下: ...

  6. IComparable和IComparer接口

    C#中,自定义类型,支持比较和排序,需要实现IComparable接口.IComparable接口存在一个名为CompareTo()的方法,接收类型为object的参数表示被比较对象,返回整型值:1表 ...

  7. JDBC 学习笔记(三)—— JDBC 常用接口和类,JDBC 编程步骤

    1. JDBC 常用接口和类 DriverManager 负责管理 JDBC 驱动的服务类,程序中主要的功能是获取连接数据库的 Connection 对象. Connection 代表一个数据库连接对 ...

  8. C#的 IComparable 和 IComparer接口及ComparableTo方法的 区别(非常重要)

    (1)https://blog.csdn.net/ios99999/article/details/77800819 C# IComparable 和 IComparer 区别 (2)https:// ...

  9. 常用接口简析3---IList和List的解析

    常用接口的解析(链接) 1.IEnumerable深入解析 2.IEnumerable.IEnumerator接口解析 3.IComparable.IComparable接口解析 学习第一步,先上菜: ...

随机推荐

  1. MS Sql Server 消除重复行 保留信息完整的一条 2011-11-26 13:19(QQ空间)

    select company ,count(company) as coun into myls from mylist group by company having count(company)& ...

  2. hdu-4471-Homework-矩阵快速幂+优化加速

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4471 题目意思: 求f(n). 当n为特殊点nk时 解题思路: 当x不为特殊点时,直接用基本的矩阵快 ...

  3. 理解git对象

    1. 首次提交,提交一个简单的文件 a.txt ,commit 之后的图如下:   如图所示,生成了 3 个对象,一个 commit 对象,一个 tree 对象,一个 blob 对象.图上蓝底是 co ...

  4. 用php 进行对文件的操作 (上)

    如何让自己磁盘中的文件夹和目录显示在网页上?那就来看一下,用php是怎么来操作他们的吧 php中文件,一般包含两块内容,文件和目录 先来一句一句的看代码,及他的作用 运行后看一下结果 file 指的是 ...

  5. .Net多线程编程—同步机制

    1.简介 新的轻量级同步原语:Barrier,CountdownEvent,ManualResetEventSlim,SemaphoreSlim,SpinLock,SpinWait.轻量级同步原语只能 ...

  6. 【使用教程】论Windows下必备的抓包工具Fiddler2如何安装证书(查看Https)

    一.写在前面 好久没更新博客了,最近也是忙着年前的一些事情,所以一直没来得及弄一些有价值的东西,还是来冒个泡.随着苹果公司要求的2017年开始上架审核必须是Https,而原本Http的上架需要提交强烈 ...

  7. 基于AFNetworking 3.0的取消已发出的网络请求

    一般情况下主动取消请求的需求不会太多 除非以下几种情况 1.比如电商应用为例 请求频繁,数据量大 2.对性能的要求比较高 3.网络环境比较差 当一个用户打开一个界面 看到的却是漫长的等待框 这时候用户 ...

  8. spring-mvc + shiro框架整合(sonne_game网站开发04)

    这篇文章讲的内容是在之前spring + mybatis + spring-mvc + freemarker框架整合的代码的基础上.有需要的可以看看我博客的前两篇文章. 另外,本文章所讲相关所有代码都 ...

  9. 简介alert()与console.log()的不同

    简单的说alert 是弹出提示而console.log是在调试工具里打日志,下面具体给大家列出alert()与console.log()的不同点, [1]alert() [1.1]有阻塞作用,不点击确 ...

  10. R语言 关联规则

    在用R语言做关联规则分析之前,我们先了解下关联规则的相关定义和解释. 关联规则的用途是从数据背后发现事物之间可能存在的关联或者联系,是无监督的机器学习方法,用于知识发现,而非预测. 关联规则挖掘过程主 ...