zoukankan      html  css  js  c++  java
  • .Net Collection的一些理解——记录一次向实习生的答疑

    公司最近进了个实习生,每天下班前我都会花一些时间来解答一下实习生的一些疑问。今天问起了关于集合排序方法Sort的一些疑问,这让我一下回到自己刚刚入行的时候。那个时候也遇到了集合排序的问题,为发现接口IComparableICompare的妙处而兴奋,还在公司的内部分享会上分享了如何使用它们来排序。现在经过多年的开发实践以及学习,对于同一个问题又有了更加深入的理解。

    一. 为什么说”实现了IEnumerable接口才能遍历”

    实习生先是问了这个问题, 其实这个问题, 非常容易解答.
    先来看看IEnumerable接口的定义:

    public interface IEnumerable
    {
        IEnumerator GetEnumerator();
    }

    这个接口非常简单,主要就是一个方法GetEnumerator,用来返回一个IEnumerator对象。
    继续深入下去,IEnumerator接口的定义如下:

    public interface IEnumerator
    {
       bool MoveNext();
          void Reset();
         object Current {  get; }
    }

    上面的IEnumerator接口定义的属性和方法,只有一个目的,就是实现如何遍历。下面具体解释一下:

    • Current属性, 用来返回当前集合项的值
    • MoveNext方法, 移动到集合对象的下一项,如果有下一项,就返回true, 如果没有,就返回false.
    • Reset(), 重置然后可以重头访问集合

    到这里,为什么foreach能够遍历集合对象的原因就是因为集合对象都实现了IEnumerable接口,提供了具体的实现来遍历集合对象。

    二. Sort()方法以及IComparable、IComparer接口

    集合类型,都有Sort()排序方法,这个函数的一个重载版本中,需要提供一个IComparer类型的接口。为什么需要使用这个接口呢?这个和排序有什么关系?
    想一想,实现排序必须的是什么?必须的是能够比较大小。对于int, string这种.Net内部类型,本身已经支持了IComparer, 也就是可以比较大小了。但是对于我们自己定义的类型,使用Sort方法是无法排序的,因为程序不知道我们对于自定义对象的排序规则, 这个时候就可以使用IComparableIComparer.

    下面举一个实际的例子, 这里我们自定义了一个类Car, 然后对Car的集合进行排序.

    public class Car
    {
           public string Name { get; set; }
           public int Year { get; set; }
           public int Seats { get; set; }
    }

    假如我们直接调用Sort方法, 就会悲剧抛出InvalidOperationException异常

    image 

    2.1 IComparable接口

    IComparable 接口提供了比较某个特定类型对象的方法. 这里来说, 我们要让Car实现IComparable 接口来达到比较Car对象的目的,从而实现排序。实现IComparable接口, 就必须实现CompareTo 方法, 具体如下:

    public class Car: IComparable
    {
           public string Name { get; set; }
           public int Year { get; set; }
           public int Seats { get; set; }
    
           public int CompareTo(object obj)
           {
               var car = (Car) obj;
               return String.CompareOrdinal(Name, car.Name);
           }
    }

    上面我们的Car对象实现了IComparable接口,按照Name字符串属性来比较. 直接运行Sort()方法,就能够得到排序结果:

    image

    2.2 IComparer接口

    IComparer接口可以提供更加丰富和灵活的排序功能。 比如, 你可能需要在不同的场合,根据不同的属性来排序.
    下面就来实现一个根据Car的Year属性来排序, 首先创建类CarYearComparer来对Car进行比较,比较是根据Year属性

    public class CarYearComparer: IComparer<Car>
    {
           public int Compare(Car x,  Car y)
           {
               if (x.Year > y.Year)
                   return 1;
               if (x.Year < y.Year)
                   return -1;
               return 0;
           }
    }

    在调用Sort方法排序的时候,需要指定使用的IComparer实现:

    cars.Sort(new CarYearComparer());

    得到的排序结果和上面的根据Name属性不同:

    image

    还可以实现一个根据Car的属性Seats排序的IComparer. 所以使用IComparer更加的灵活

    3. 面向对象设计思想

    Collection中的Sort()方法很好地遵循了开放封闭原则,既很好地完成了排序的功能,同时又开放出了入口,让你可以为排序自定义规则。

    下面是我个人的一些个人理解:
    一个类应该做自己擅长的事情和核心的事情(单一职责),把不擅长的交给别人。但是这个”别人“是不是任何人都可以呢?当然不是,为了更好的限定别人,我们使用了接口限定。
    当一个类依赖于抽象(也就是接口),那么这个类的适用范围就更加广,就能够更加超脱。老子一句”道可道,非常道;名可名,非常名”,正是没有具体化,所以可以解释万物。

    更多的面向对象设计原则,参照http://www.360doc.com/content/11/0521/00/3554006_118258005.shtml

    最后附上本文相关源代码: SortDemo

  • 相关阅读:
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第4章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第3章 读书笔记(待更新)
    Algebra, Topology, Differential Calculus, and Optimization Theory For Computer Science and Machine Learning 第1,2章 读书笔记(待更新)
    Tkinter的Message组件
    Git 实操/配置/实践
    mysq5.7.32-win安装步骤
    行为型模式之模板方法
    结构型模式之组合模式
    结构型模式之享元模式
    结构型模式之外观模式
  • 原文地址:https://www.cnblogs.com/JustRun1983/p/3912257.html
Copyright © 2011-2022 走看看