一个集合可否排序,要看系统知不知道排序的规则,像内建的系统类型,int ,string,short,decimal这些,系统知道怎么排序,而如果一个集合里面放置的是自定义类型,比如自己定义了一个Product类型,要把它排序,系统是不知道怎么办的。
那么,如何告知系统排序的规则呢?有以下几种方法:
1:对类实现IComparable接口,示例如下:
代码1
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SortTeset 7 { 8 class Product :IComparable 9 { 10 public string Name { get; private set; } 11 public decimal Price { get; private set; } 12 13 public Product(string name, decimal price) 14 { 15 Name = name; 16 Price = price; 17 } 18 19 public Product() { } 20 21 public static List<Product> GetSampleProduct() 22 { 23 return new List<Product> 24 { 25 new Product{Name="Watch",Price=12345.56m}, 26 new Product{Name="Knife",Price=224.50m}, 27 new Product{Name="Rope",Price=12.50m}, 28 new Product{Name="ETorch",Price=58.5m} 29 }; 30 } 31 32 public override string ToString() 33 { 34 return string.Format("{0} : {1}", Name, Price); 35 } 36 37 int IComparable.CompareTo(object obj) 38 { 39 Product temp = (Product)obj; 40 return this.Name.CompareTo(temp.Name); 41 } 42 43 } 44 45 class Program 46 { 47 static void Main(string[] args) 48 { 49 List<Product> ProductSample = Product.GetSampleProduct(); 50 foreach (Product tmp in ProductSample) 51 { 52 Console.WriteLine(tmp); 53 } 54 55 Console.WriteLine(); 56 57 ProductSample.Sort(); 58 59 foreach (Product tmp in ProductSample) 60 { 61 Console.WriteLine(tmp); 62 } 63 } 64 } 65 }
其中最主要的是这句:
class Product :IComparable
跟这句:
int IComparable.CompareTo(object obj)
{
Product temp = (Product)obj;
return this.Name.CompareTo(temp.Name);
}
就是实现了IComparable.CompareTo()这个方法。然后就可以直接调用 SomeProductList.Sort();方法来进行排序。
2:指定IComparer 类的对象。
代码3
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SortTeset2 7 { 8 class Product 9 { 10 public string Name { get; private set; } 11 public decimal Price { get; private set; } 12 13 public Product(string name, decimal price) 14 { 15 Name = name; 16 Price = price; 17 } 18 19 public Product() { } 20 21 public static List<Product> GetSampleProduct() 22 { 23 return new List<Product> 24 { 25 new Product{Name="Watch",Price=12345.56m}, 26 new Product{Name="Knife",Price=224.50m}, 27 new Product{Name="Rope",Price=12.50m}, 28 new Product{Name="ETorch",Price=58.5m} 29 }; 30 } 31 32 public override string ToString() 33 { 34 return string.Format("{0} : {1}", Name, Price); 35 } 36 } 37 38 39 class ProductNameComparer : IComparer<Product> 40 { 41 public int Compare(Product first, Product second) 42 { 43 return first.Name.CompareTo(second.Name); 44 } 45 } 46 47 class Program 48 { 49 static void Main(string[] args) 50 { 51 List<Product> ProductSample = Product.GetSampleProduct(); 52 foreach (Product tmp in ProductSample) 53 { 54 Console.WriteLine(tmp); 55 } 56 57 Console.WriteLine(); 58 59 ProductSample.Sort(new ProductNameComparer()); 60 61 foreach (Product tmp in ProductSample) 62 { 63 Console.WriteLine(tmp); 64 } 65 } 66 } 67 } 68
这儿我们新定义了一个类:ProductNameComparer,这个类实现了泛型接口:IComparer<Product>,然后在
ProductSample.Sort(new ProductNameComparer());
语句中我们提供了一个比较器对象。
这种方法看上去不如直接实现ICompareable接口来得简洁。
这种方法可以用匿名方法进行改进:
代码4
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SortTeset3 7 { 8 class Product 9 { 10 public string Name { get; private set; } 11 public decimal Price { get; private set; } 12 13 public Product(string name, decimal price) 14 { 15 Name = name; 16 Price = price; 17 } 18 19 public Product() { } 20 21 public static List<Product> GetSampleProduct() 22 { 23 return new List<Product> 24 { 25 new Product{Name="Watch",Price=12345.56m}, 26 new Product{Name="Knife",Price=224.50m}, 27 new Product{Name="Rope",Price=12.50m}, 28 new Product{Name="ETorch",Price=58.5m} 29 }; 30 } 31 32 public override string ToString() 33 { 34 return string.Format("{0} : {1}", Name, Price); 35 } 36 } 37 38 class Program 39 { 40 static void Main(string[] args) 41 { 42 List<Product> ProductSample = Product.GetSampleProduct(); 43 foreach (Product tmp in ProductSample) 44 { 45 Console.WriteLine(tmp); 46 } 47 48 Console.WriteLine(); 49 50 ProductSample.Sort(delegate(Product first, Product second) 51 { 52 return first.Name.CompareTo(second.Name); 53 }); 54 55 foreach (Product tmp in ProductSample) 56 { 57 Console.WriteLine(tmp); 58 } 59 } 60 } 61 } 62
这一次,不用定义那个类,然后使用它的方法了,而是直接填充delegate接口。
这种方法还可以进一步用Lambda表达式改进,如下:
代码5
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SortTeset4 7 { 8 class Product 9 { 10 public string Name { get; private set; } 11 public decimal Price { get; private set; } 12 13 public Product(string name, decimal price) 14 { 15 Name = name; 16 Price = price; 17 } 18 19 public Product() { } 20 21 public static List<Product> GetSampleProduct() 22 { 23 return new List<Product> 24 { 25 new Product{Name="Watch",Price=12345.56m}, 26 new Product{Name="Knife",Price=224.50m}, 27 new Product{Name="Rope",Price=12.50m}, 28 new Product{Name="ETorch",Price=58.5m} 29 }; 30 } 31 32 public override string ToString() 33 { 34 return string.Format("{0} : {1}", Name, Price); 35 } 36 } 37 38 class Program 39 { 40 static void Main(string[] args) 41 { 42 List<Product> ProductSample = Product.GetSampleProduct(); 43 foreach (Product tmp in ProductSample) 44 { 45 Console.WriteLine(tmp); 46 } 47 48 Console.WriteLine(); 49 50 ProductSample.Sort((first,second)=>first.Name.CompareTo(second.Name)); 51 52 foreach (Product tmp in ProductSample) 53 { 54 Console.WriteLine(tmp); 55 } 56 } 57 } 58 } 59
变态的是,还可以进一步改进,使用扩展方法,如下:
代码6
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace SortTeset5 7 { 8 class Product 9 { 10 public string Name { get; private set; } 11 public decimal Price { get; private set; } 12 13 public Product(string name, decimal price) 14 { 15 Name = name; 16 Price = price; 17 } 18 19 public Product() { } 20 21 public static List<Product> GetSampleProduct() 22 { 23 return new List<Product> 24 { 25 new Product{Name="Watch",Price=12345.56m}, 26 new Product{Name="Knife",Price=224.50m}, 27 new Product{Name="Rope",Price=12.50m}, 28 new Product{Name="ETorch",Price=58.5m} 29 }; 30 } 31 32 public override string ToString() 33 { 34 return string.Format("{0} : {1}", Name, Price); 35 } 36 } 37 38 class Program 39 { 40 static void Main(string[] args) 41 { 42 List<Product> ProductSample = Product.GetSampleProduct(); 43 foreach (Product tmp in ProductSample) 44 { 45 Console.WriteLine(tmp); 46 } 47 48 Console.WriteLine(); 49 50 foreach (Product tmp in ProductSample.OrderBy(p=>p.Name)) 51 { 52 Console.WriteLine(tmp); 53 } 54 } 55 } 56 }
“这里似乎调用了一个OrderBy方法,但查阅一下MSDN,就会发现这个方法在List<Product>中根本不存在。之所以能调用它,是由于存在一个扩展方法。这里实际不再是"原地"对列表进行排序,而只是按特定的顺序获取列表的内容。有的时候,你需要更改实际的列表;但有的时候,没有任何副作用的排序显得更"善解人意"。重点在于,现在的写法更简洁,可读性更好(当然是在你理解了语法之后)。我们的想法是"列表按名称排序",现在的代码正是这样做的。并不是"列表通过将一个产品的名称与另一个产品的名称进行比较来排序",就像C#
2代码所做的那样。也不是使用知道如何将一个产品与另一个产品进行比较的另一个类型的实例来按名称排序。这种简化的表达方式是C# 3的核心优势之一。既然单独的数据查询和操作是如此的简单,那么在执行更大规模的数据处理时,仍然可以保持代码的简洁性和可读性,这进而鼓励开发者以一种"以数据为中心"的方式来观察世界。”
最后这两步的语法,绝对是一个会用其它语言比如C/C++,VB的人所无法明白的,C#进化速度真是快。。。。。。。