本次不会改变product类型,会使用产品列表,并按名称排序,然后找出最贵的产品
一、按名称对产品进行排序
以特定顺序显示一个列表的最简单方式就是先将列表排好序,在遍历显示其中的项。
(一) 在.net1.1中,这要求使用ArrayList.Sort,要求提供一个IComparer实现。也可以让product类型实现IComparable,但那就只能定义一种排序顺序。很容易就会想到,以后除了需要按名称排序,还可能需要按价格排序
使用IComparer对ArrayList进行排序
class productNameComparer : IComparer { public int Compare(object x, object y) { Product first = (Product)x; Product second = (Product)y; return first.Name.CompareTo(second.Name); } } ...... ArrayList products = Product.GetSanpleProducts(); products.Sort(new productNameComparer()); foreach (Product product in products) { Console.WriteLine(product); } Console.ReadKey();
要注意的第一件事是:必须引入一个的类型来帮助排序。虽然这并不是一个很大的问题,但假如在一个地方只是项按名称进行排序,就会感觉编译工作过于繁重。其次,注意Comparer方法中强制类型转换。强制类型转换相当于告诉编译器:“我知道发比你多一点点,”但是,也就意味着可能是错误的。如果GetSanpleProducts返回的是ArrayList包含一个字符串,那么代码会出错——因为在比较时试图将字符串强制转型为product。
(二)在给出排序列表的代码中也进行了强制类型转换。这个转换不如刚才的转换显示,因为是编译器自动进行的。foreach循环会隐式将列表中的每个元素转换为product类型。这样的情况在执行时会失败,在C#2“泛型”可以帮助解决这些问题
使用Icomparer对List<product>进行排序
class productNameComparer : IComparer<Product> { public int Compare(Product x, Product y) { return x.Name.CompareTo(y.Name); } } ...... List<Product> products = Product.GetSanpleProducts(); products.Sort(new productNameComparer()); foreach (Product product in products) { Console.WriteLine(product); } Console.ReadKey();
对产品进行比较的代码变得更简单,因为一开始提供的就是product。不需要进行强制类型转换。类似地,foreach循环中隐式的类型转换也被取消了。编译器仍然会考虑将序列中的源类型转换为变量的目标类型,但它知道这时两种类型均为product,因此没必要产生任何用于转换的代码。
希望能直接指定要进行的比较,就能开始对产品进行排序,而不需要实现一个接口来做这件事。
使用Comparison对List<product>进行排序
List<Product> products = Product.GetSanpleProducts(); products.Sort(delegate (Product x, Product y) { return x.Name.CompareTo(y.Name); }); foreach (Product product in products) { Console.WriteLine(product); } Console.ReadKey();
现在已经不在需要productNameComparer类型了。以粗体印刷的语句实际会创建一个委托实例,将这个委托实例提供给Sort方法来执行比较
(三)已经修正了在C#1的版本中不喜欢的所有东西。但是,这并不是说C#3不能做到更好。首先,将匿名方法替换成一种更简洁的创建委托实例的方式
lambda表达式中使用Comparison排序
List<Product> products = Product.GetSanpleProducts(); products.Sort((x, y) => x.Name.CompareTo(y.Name)); foreach (Product product in products) { Console.WriteLine(product); } Console.ReadKey();
看到了一种奇怪的语法(一个lambda表达式),它仍然创建了一个Comparison<product>委托,只是代码量减少。这里不必使用delegate关键字来引入委托,甚至不需要指定参数类型
除此之外,使用C#3还有其他好处,现在,可以轻松的按顺序打印名称,同时不必修改原始产品列表。
使用扩展方法对List<product>进行排序
List<Product> products = Product.GetSanpleProducts(); foreach (Product product in products.OrderBy(p=>p.Name)) { Console.WriteLine(product); } Console.ReadKey();
这里似乎调用一个OrderBy方法,但查阅一下MSDN,就会发现这个方法在LIst<product>中根本不存在。之所以能调用它,是由于存在一个扩展方法。这里实际不在是“原地”对列表进行排序,而只是按特定的顺序获取列表的内容。有时,需要更改实际的列表;但有时,没有任何副作用的排序显得更“善解人意”。
(四)总结
重点在于,现在的写法更简洁,可读性更好。想法是“列表按名称排序”,现在的代码正是这样做的。并不是“列表通过将产品的名称与另一个产品的名称进行比较来排序”,就像C#2代码所做的那样。也不是使用知道如何将一个产品与另一个产品进行比较的另一个类型的实例来排序。这种简化的表达方式是C#3的核心有事之一。既然单独的数据查询和操作是如此简单,那么在执行更大规模的数据处理时,仍然可以保存代码的简洁性和可读性,这进而鼓励开发者以一种“以数据为中心”的方式来观察世界。
在C#2和C#3中用于简化排序的特性
1.C#1:弱类型的比较功能不支持委托排序
2.C#2强类型的比较更能,委托比较,匿名方法
3.C#3:表达式,扩展方法,允许列表保持为排序状态