一、以 Product 类为例
public class Product
{
string name;
public string Name
{
get { return name; }
}
decimal price;
public decimal Price
{
get { return price; }
}
public Product(string name, decimal price)
{
this.name = name;
this.price = price;
}
public static ArrayList GetSampleProducts()
{
ArrayList list = new ArrayList();
list.Add(new Product("West Side Story", 9.99m));
list.Add(new Product("Assassins", 14.99m));
list.Add(new Product("Frogs", 13.99m));
list.Add(new Product("Sweeney Todd", 10.99m));
return list;
}
public override string ToString()
{
return string.Format("{0}: {1}", name, price);
}
}
1. C# 1.0 使用 ArrayList 添加列表。
C# 1 代码中的3个局限:
- ArrayList 是一个可以动态调整大小的数组,且可以存储任何类型的对象。
- 编译时无法检查类型错误。(类型安全)
- 如果存储的是 Object 类型的对象,就会涉及到装箱(boxing)和拆箱(unboxing)操作。(性能)
- 属性的赋值方法是公共的。
- 用于创建属性和变量的代码很复杂。
- string _name;
- public string Name { get { return _name; } }
2. C# 2 中的强类型集合
List<Product> List = now List<Product>();
ArrayList 换成 强类型集合 List。List<类型> 编译时就能捕获异常。
- 提高了类型安全性
- 避免了装箱和拆箱
- 操作更加清晰可读和易于理解。
属性拥有了私有赋值方法。
private set { name = value; }
3. C# 3 中自动实现的属性
自动实现的属性和更简单的初始化。
public string Name { get; private set; }
4. C# 4 中的命名实参
在调用方法时可以指定参数名称。
new Product { Name = "West Side Story", Price = 9.99m },
演变历程
二、按名称对产品进行排序
class ProductNameComparer: IComparer
{
public int Compare(object x, object y)
{
Product first = (Product)x;
Product second = (Product)y;
return first.Name.CompareTo(second.Name);
}
}
// Call
ArrayList products = Product.GetSampleProducts();
products.Sort(new ProductNameComparer());
foreach (Product product in products)
{
Console.WriteLine(product);
}
1. C# 1 中使用 IComparer 对 ArrayList 进行排序
// IComparer 源码
public interface IComparer
{
int Compare(object x, object y);
}
C# 1 代码中的局限:
- 引入了一个额外的类型 ProductNameComparer 来帮助排序,繁重。
- 在实现接口的 Compare 方法中,需要强制类型转换。
- 遍历 ArrayList 类型的 products 集合时,也会强制转换成 Product。
Sort 使用的是 ArrayList 类中的 Sort(IComparer comparer) 方法。
2. C# 2 使用 IComparer<Product> 对 List<Product> 进行排序
// 弱类型变成强类型
class ProductNameComparex: IComparer<Product>
{
public int Compare(Product x, Product y)
{
return x.Name.CompareTo(y.Name);
}
}
List<Product> products = Product.GetSampleProducts();
改善局限 2、3:实现接口使用了泛型 ICompare<T>,即强类型,也避免了 Compare 方法中的可能会有的装箱拆箱。泛型 List<T>也一样。
Sort 使用的是 List<T> 类中的 Sort(IComparer<T> comparer) 方法。
// IComparer<T> 源码
public interface IComparer<in T>
{
int Compare(T x, T y);
}
3. C# 2 使用 Comparison<Product> 对 List<Product> 进行排序
// 使用一个委托来比较
products.Sort(
delegate(Product x, Product y)
{
return x.Name.CompareTo(y.Name);
}
);
改善局限1:不需要实现一个接口来实现排序,而是使用一个委托来比较
Sort 使用的是 List<T> 类中的 Sort(Comparison<T> comparison) 方法
4. C# 3 在 Lambda 表达式中使用 Comparison<Product> 来进行排序
// 从 匿名方法 到 Lambda表达式
products.Sort((x, y) => x.Name.CompareTo(y.Name));
继续改善局限1
5. C# 3 使用一个扩展方法对 List 进行排序
// 使用扩展方法 OrderBy
foreach (Product product in products.OrderBy(p => p.Name))
{
Console.WriteLine(product);
}
本意的想法就是“列表按名称排序”,现在的代码就更符合语义。并不是像最初那样“列表通过将一个产品的名称与另一个产品的名称进行比较来排序”,像C# 2.0代码所展示的那样。也不是使用知道如何将一个产品与另一个产品进行比较的另一个类型的实例来按名称排序。
OrderBy 使用的是 Enumerable 类中的方法:IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
演变历程
三、找出列表中符合条件的所有元素
1. C# 1 循环、测试、打印是一体的
// 循环、测试、打印 这三个任务是纠缠在一起的
ArrayList products = Product.GetSampleProducts();
foreach (Product product in products)
{
if (product.Price > 10m)
{
Console.WriteLine(product);
}
}
C# 1 条件和操作紧密耦合,两者都是硬编码的
2. C# 2 测试和打印分开进行
// 版本1
List<Product> products = Product.GetSampleProducts();
Predicate<Product> test = delegate (Product p) { return p.Price > 10m; }; //匿名方法
List<Product> matches = products.FindAll(test);
Action<Product> print = Console.WriteLine;
matches.ForEach(print);
// 版本2
products.FindAll(
delegate (Product p) { return p.Price > 10; }
).ForEach(Console.WriteLine);
C# 2 条件和委托分开,匿名方法使委托变得简单
3. C# 3 Lambda 表达式来 测试
foreach(Product p in products.Where(p => p.Price > 10))
{
Console.WriteLine(p);
}
C# 3 Lambda 表达式使条件变得更容易阅读