我们将介绍C#数组排序与对象大小比较
包括一些实例代码以及IComparable
IComparable和IComparer三大接口的用法
从个小例子开始
int[] intArray = new int[]{}ArraySort(intArray)ArrayForEach<int>(intArray(i)=>ConsoleWriteLine(i))这个例子定义了一个int数组然后使用ArraySort(arr)静态方法对此数组进行排序最后输出排序后的数组以上例子将毫无意外的依次输出
为什么Array的Sort方法可以正确的对int数组进行排序呢我们自定义类可以吗?试试看如下代码
public class Student { public int Age { get set } public string Name { get set } public int Score { get set } } static void Main(string[] args)
{ Student[] students = new Student[]{ new Student(){Age = Name=张三Score=}new Student(){Age = Name=李四Score=}new Student(){Age = Name=王五Score=}new Student(){Age = Name=赵六Score=}new Student(){Age = Name=司马Score=}}ConsoleWriteLine(——默认排序输出——)ArraySort(students)ArrayForEach<Student>(students(s)=>ConsoleWriteLine(stringFormat({}{}岁了他的分数是{}sNamesAgesScore)))ConsoleRead()}我们定义了Student类然后同样对他的数组进行排序程序正确的编译通过但是运行出错运行时抛出了异常SystemInvalidOperationException{Failed to compare two elements in the array}这个异常的InnerException是ArgumentException{At least one object must implement IComparable}运行时异常说明我们要使用ArraySort(arr)静态方法必须得保证数组中有一个元素实现IComparable接口既然如此我们就让Student类实现IComparable接口
public class Student IComparable { public int Age { get set } public string Name { get set } public int Score { get set } /// <summary> /// 实现IComparable接口用Age做比较/// </summary> /// <param name=obj>比较对象</param> /// <returns>比较结果</returns> public int CompareTo(object obj)
{ if (obj is Student)
{ return AgeCompareTo(((Student)obj)Age)} return }在Student类中实现了IComparable接口在CompareTo方法中比较Student的Age属性这一次再次编译运行程序正常的输出了按照年龄排序的Student数组
假如说我们要对Student的Score属性进行排序该怎么办呢? Student类实现的IComparable接口只能按照一种属性排序呀
这个是很容易实现的net的类库开发者早为我们准备了另一个接口IComparer<T>接口用来实现比较类型T的两个实例如下StudentScoreComparer类实现了对Student按照Score属性比较的IComparer<Student>
public class StudentScoreComparer IComparer<Student> { public int Compare(Student x Student y)
{ return xScoreCompareTo(yScore)}现在我们可以使用下面代码对Student数组按照Score属性进行排序
ConsoleWriteLine(——按分数排序输出——)
ArraySort(students new StudentScoreComparer())
ArrayForEach<Student>(students (s) => ConsoleWriteLine(stringFormat({}{}岁了他的分数是{} sName sAge sScore)))
不过一个简单的按照Score属性排序再定义一个类是不是有点大题小作呀有没有更好的办法呢?当然有为我们准备了比较对象大小的委托Comparison<T>我们可以使用拉姆达表达式或者匿名委托直接排序如下代码实现
ConsoleWriteLine(——按分数排序输出——)ArraySort(students (s s) => sScoreCompareTo(sScore))ArrayForEach<Student>(students (s) => ConsoleWriteLine(stringFormat({}{}岁了他的分数是{} sName sAge sScore)))完整代码示例如下
using Systemusing SystemCollectionsGenericusing SystemLinqusing SystemTextnamespace SortingInCSharp { class Program { public class Student IComparable { public int Age { get set } public string Name { get set } public int Score { get set } /// <summary> /// 实现IComparable接口用Age做比较/// </summary> /// <param name=obj>比较对象</param> /// <returns>比较结果</returns> public int CompareTo(object obj)
{ if (obj is Student)
{ return AgeCompareTo(((Student)obj)Age)} return } static void Main(string[] args)
{ Student[] students = new Student[]{ new Student(){Age = Name=张三Score=}new Student(){Age = Name=李四Score=}new Student(){Age = Name=王五Score=}new Student(){Age = Name=赵六Score=}new Student(){Age = Name=司马Score=}}ConsoleWriteLine(——默认排序输出——)ArraySort(students)ArrayForEach<Student>(students (s) => ConsoleWriteLine(stringFormat({}{}岁了他的分数是{} sName sAge sScore)))ConsoleWriteLine(——按分数排序输出——)ArraySort(students new StudentScoreComparer())ArrayForEach<Student>(students (s) => ConsoleWriteLine(stringFormat({}{}岁了他的分数是{} sName sAge sScore)))ConsoleWriteLine(——按分数排序输出——)ArraySort(students (s s) => sScoreCompareTo(sScore))ArrayForEach<Student>(students (s) => ConsoleWriteLine(stringFormat({}{}岁了他的分数是{} sName sAge sScore)))ConsoleRead()} public class StudentScoreComparer IComparer<Student> { public int Compare(Student x Student y)
{ return xScoreCompareTo(yScore)}总结
在C#中有三个关于比较对象大小的接口分别是IComparableIComparable<T>和IComparer<T> IComparable和IComparable<T>是类本身实现的在实例之间比较大小的行为定义IComparer<T>是定义在被比较类之外的专门比较两个T类型对象大小的行为另外还有一个用于比较的委托定义Comparison<T>可以让我们用拉姆达表达式或者匿名委托或方法更方便的排序