1.1 数据类型
C#1.0
[Description("Listing 1.01")] 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); } }
- ArrayList不是类型安全的
- 属性的Get和Set的Access只能一致
- 用于创建属性和变量的代码复杂(除属性外必须再声明一个变量)
C#2.0
public class Product { string name; public string Name { get { return name; } private set { name = value; } } decimal price; public decimal Price { get { return price; } private set { price = value; } } public Product(string name, decimal price) { Name = name; Price = price; } public static List<Product> GetSampleProducts() { List<Product> list = new List<Product>(); 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); } }
- 解决了C#1.0 里三个问题的前两个,(泛型,Private Set)
C#3.0
class Product { public string Name { get; private set; } public decimal Price { get; private set; } public Product(string name, decimal price) { Name = name; Price = price; } Product() { } public static List<Product> GetSampleProducts() { return new List<Product> { new Product { Name="West Side Story", Price = 9.99m }, new Product { Name="Assassins", Price=14.99m }, new Product { Name="Frogs", Price=13.99m }, new Product { Name="Sweeney Todd", Price=10.99m} }; } public override string ToString() { return string.Format("{0}: {1}", Name, Price); } }
- 通过自动属性解决了C#1.0里的第三个问题。
C#4.0
public class Product { readonly string name; public string Name { get { return name; } } decimal? price; public decimal? Price { get { return price; } } public Product(string name, decimal? price = null) { this.name = name; this.price = price; } public static List<Product> GetSampleProducts() { List<Product> list = new List<Product>(); list.Add(new Product(name: "West Side Story", price: 9.99m)); list.Add(new Product(name: "Assassins", price: 14.99m)); list.Add(new Product(name: "Frogs", price: 13.99m)); list.Add(new Product(name: "Sweeney Todd", price: 10.99m)); list.Add(new Product(name: "Unpriced")); return list; } public override string ToString() { return string.Format("{0}: {1}", name, price); } }
- 命名实参带来了清晰的初始化代码。
1.2 排序和过滤
1.2.1 按名称对产品进行排序
C#1.0
class ArrayListSort { class ProductNameComparer : IComparer { public int Compare(object x, object y) { Product first = (Product)x; Product second = (Product)y; return first.Name.CompareTo(second.Name); } } static void Main() { ArrayList products = Product.GetSampleProducts(); products.Sort(new ProductNameComparer()); foreach (Product product in products) { Console.WriteLine(product); } } }
- 必须引入一个额外的类来进行排序
- 非类型安全的
C#2.0
class ListSortWithComparer { class ProductNameComparer : IComparer<Product> { public int Compare(Product first, Product second) { return first.Name.CompareTo(second.Name); } } static void Main() { List<Product> products = Product.GetSampleProducts(); products.Sort(new ProductNameComparer()); foreach (Product product in products) { Console.WriteLine(product); } } }
- 用以上方法排序,和C#1.0一样同样需要引入一个新的类,但是由于C#2.0支持泛型,解决了类型安全的问题。
class ListSortWithComparisonDelegate { static void Main() { List<Product> products = Product.GetSampleProducts(); products.Sort(delegate(Product first, Product second) { return first.Name.CompareTo(second.Name); } ); foreach (Product product in products) { Console.WriteLine(product); } } } }
- 使用委托(Comparison)可以避免创建一个新的类(ProductNameComparer),将创建的委托传给Sort方法来执行比较。(匿名方法)
C#3.0
class ListSortWithLambdaExpression { static void Main() { List<Product> products = Product.GetSampleProducts(); products.Sort( (first, second) => first.Name.CompareTo(second.Name) ); foreach (Product product in products) { Console.WriteLine(product); } } }
- 使用兰巴达表达式来代替委托。
class ListOrderWithExtensionMethod { static void Main() { List<Product> products = Product.GetSampleProducts(); foreach (Product product in products.OrderBy(p => p.Name)) { Console.WriteLine(product); } } }
- 使用到了扩展方法(Orderby),允许列表保持未排序状态(products)本身没有排序。
1.2.2 查询集合
C#1.0
class ArrayListQuery { static void Main() { ArrayList products = Product.GetSampleProducts(); foreach (Product product in products) { if (product.Price > 10m) { Console.WriteLine(product); } } } }
- 用foreach循环,用if判断,再用Console.WritleLine显示产品,这三个任务的依赖性一目了然。
C#2.0
class ListQueryWithDelegates { static void Main() { 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); } }
class ListQueryWithDelegatesCompact { static void Main() { List<Product> products = Product.GetSampleProducts(); products.FindAll(delegate(Product p) { return p.Price > 10; }) .ForEach(delegate(Product p) { Console.WriteLine(p); }); } }
- 测试和打印分开进行
C#3.0
class ListQueryWithLambdaExpression { static void Main() { List<Product> products = Product.GetSampleProducts(); foreach (Product product in products.Where(p => p.Price > 10)) { Console.WriteLine(product); } } }
- 使用兰巴达表达式
1.3处理未知数据 (Nullable<T>)
1.4Linq
1.5Com和动态类型(Dynamic)
1.6 async/await
private async void CheckProduct(object sender, EventArgs e) { try { // Only permit one lookup at a time productCheckButton.Enabled = false; statusLabel.Text = "Checking..."; nameValue.Text = ""; priceValue.Text = ""; stockValue.Text = ""; string id = idInput.Text; Task<Product> productLookup = directory.LookupProductAsync(id); Task<int> stockLookup = warehouse.LookupStockLevelAsync(id); Product product = await productLookup; if (product == null) { statusLabel.Text = "Product not found"; // We don't care about the result of the stock check return; } nameValue.Text = product.Name; priceValue.Text = product.Price.ToString("c"); int stock = await stockLookup; stockValue.Text = stock.ToString(); statusLabel.Text = "Ready"; } finally { // However we finish this method, allow another lookup productCheckButton.Enabled = true; } }