深入理解C#(第3版)-- 第1章 C#开发的进化史(学习笔记)
1.1.1 C#1中定义的产品类型
代码清单1-1 Product类型(C#1)
using System.Collections; 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 Arraytist 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("Froge", 13.99m)); list.Add(new Product("Sweeney Todd", 10.99m)); return list; } public override string Tostring() { return string.Format("{o}:{1}", name, price); } }
代码存在如下3个局限:
- ArrayList没有提供与其内部内容有关的编译时信息。不慎在GetSampleProducts创建的列表中添加一个字符串是完全有可能的,而编译器对此没有任何反应。
- 代码中为属性提供了公共的取值方法,这意味着如果添加对应的赋值方法,那么赋值方法也必须是公共的。
- 用于创建属性和变量的代码很复杂。
1.1.2 C#2中的强类型集合
针对上面列出的前两项,包含C#2中最重要的改变:泛型。新的内容用粗体列出。
代码清单1-2 强类型集合和私有的赋值方法(C#2)
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 = now List<Product>(); list.Add(new Product("West Side Story", 9.99m)); list.Add(new Product("A8sagsing", 14.99m)); list.Add(new Product("Frogen", 13.99m)); list.Add(new Product("Sweeney Todd", 10.99m)); return list; } public override string ToString() { return string.Format("{o}:{1}", name, price); } }
现在,属性拥有了私有的赋值方法(我们在构造函数中使用了这两个赋值方法)。并且它能非常“聪明”地猜出ist<Product>是告知编译器列表中只能包含Product。
1.1.3 C#3中目动实现的属性
代码清单1-3 自动实现的属性和更简单的初始化(C#3)
using System. Collections. Generic; 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 = "A#8assins", Price = 14.99m}, new Product { Name = "Frog8", Price = 13.99m}, new Product { Name = "gweeney Todd", Price = 10.99m} }; } public override string Tostring() { return string. Format("{0}:{1)", Name, Price); } }
1.1.4 C#4中的命名实参
C#4允许我们在调用构造函数时指定实参的名称
代码清单1-4 命名实参带来了清晰的初始化代码(C#4)
using System.Collections.Generic; public class Product { readonly string name; public string Name { get { return name; } } readonly decimal price; public decimal Price { get { return price; } } public product(string name, decimal price) { this.name = name; this.price = price; } public static List<Product> GetSampleProducts() { return new List<Product> { new Product(name: "West 8ide 8tory", price: 9.99m), new Product(name: "A8sassing", 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); } }
该特性的好处不是很明显,但当方法或构造函数包含多个参数时,它可以使代码的含义更加清楚—特别是当参数类型相同,或某个参数为null时。

1.2排序和过滤
1.2.1按名称对产品进行排序
实现了IComparer
代码清单1-5 使用IComparer对ArrayList进行排序(C#1)
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.GetSampleProducts(); products.Sort(new ProductNameComparer());
“泛型”
代码清单1-6 使用IComparer<Product>对List<Product>进行排序(C#2)
class ProductNameComparex: IComparer<Product> { public int Compare(Product x, Product y) { return x.Name.CompareTo(y.Name); } }
代码清单1-7 使用Comparison<Product>对List<Product>进行排序(C#2)
producta.Sort( delegate(Product x, Product y) { return x.Mame.Comparero(y.Mame); } );
能直接指定要进行的比较,就能开始对产品进行排序,而不需要实现一个接口来做这件事。
代码清单1-8 在使用Lambda表达式中使用Comparison<Product>进行排序(C#3)
product.Sort((x, y) => x.Name.Comparero(y.Name));
将匿名方法替换成一种更简洁的创建委托实例的方式
代码清单1-9 在使用一个扩展方法List<Product>进行排序(C#3)
products.OrderBy(p =>p.Name);

1.2.2查询集合
代码清单1-10 循环、测试和打印(C# 1 )
ArrayList products = Product.GetSampleProducts(); foreach (Product product in products) { if (product.Price > 10m) { Console.WriteLine(product); } }
代码清单1-11 测试和打印分开进行(C# 2 )
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);
print 变量的初始化使用了C# 2 的另一个特性——方法组转换,它简化了从现有方法创建委托的过程。
代码清单1-13 用Lambda表达式来测试(C# 3 )
products.Where(p =>p.Price >10)

1.3 处理未知数据
假定产品列表不仅包含现售的产品,还包括尚未面市的产品。某些情况下,我们可能不知道价格。
如果decimal是引用类型,那么只需使用null来表示未知的价格。
1.3.1 表示未知的价格
在C# 1 中如何表示?有3种常见的解决方案:
围绕decimal创建一个引用类型包装器;
维护一个单独的Boolean标志,它表示价格是否已知;
使用一个“魔数”(magic value )(比如 decimal.MinValue )来表示未知价格。
.NET 2.0 通过引入Nullable<T> 结构
在C# 3 中为了检查一个价格是否已知,可以把它同null比较,或者使用HasValue 属性。
1.3.2 可选参数和默认值
有时你并不想给出方法所需的所有东西,比如对于某个特定参数,你可能总是会使用同样的值。传统的解决方案是对该方法进行重载,现在C# 4引入的可选参数(optional parameter )可以简化这一操作。
public Product(string name, decimal? price = nul1) { ... }

1.4 LINQ简介
LINQ(Language Integrated Query,语言集成查询),是 C# 3的核心。顾名思义,LINQ是关于查询的,其目的是使用一致的语法和特性,以一种易阅读、可组合的方式,使对多数据源的查询变得简单。
1.4.1 查询表达式和进程内查询
查询表达式
隐式类型局部变量(implicitly typed local variable),它使用var 上下文关键字声明。
代码清单1-16 连接(joining )、过滤(filtering)、排序(ordering)和投影(projecting )(C# 3 )
List<Product> products = Product.GetSampleProducts(); List<Supplier> suppliers = Supplier.GetSampleSuppliers(); var filtered = from p in products join s in suppliers on p.SupplierID equals s.SupplierID where p.Price > 10 orderby s.Name, p.Name select new { SupplierName = s.Name, ProductName = p.Name }; foreach (var v in filtered) { Console.WriteLine("Supplier={0}; Product={1}", v.SupplierName, v.ProductName); }
1.4.2 查询XML
代码清单1-17 用LINQ to XML 对XML文件进行“复杂”的处理(C# 3 )
XDocument doc = XDocument.Load("data.xml"); var filtered = from p in doc.Descendants("Product") join s in doc.Descendants("Supplier") on (int)p.Attribute("SupplierID") equals (int)s.Attribute("SupplierID") where (decimal)p.Attribute("Price") > 10 orderby (string)s.Attribute("Name"), (string)p.Attribute("Name") select new { SupplierName = (string)s.Attribute("Name"), ProductName = (string)p.Attribute("Name") }; foreach (var v in filtered) { Console.WriteLine("Supplier={0}; Product={1}", v.SupplierName, v.ProductName); }
1.4.3 LINQ to SQL
为什么要将所有数据都从数据库里“拽”回来,再应用这些.NET查询和排序呢?为什么不直接让数据库来做这些事情呢?那不正是它擅长的事情吗?事实上,这正是LINQ to SQL所做的事情。发出了一个数据库请求,它基本上被转换为SQL 查询。虽然查询是用C#代码来表示的,但却是作为SQL 来执行的。
1.5 COM(Component Object Model)和动态类型
LINQ是C# 3 的主要内容,而互操作性是C# 4 最重要的主题。
1.5.1 简化COM互操作
使用命名实参
C# 4还支持命名索引器
1.5.2 与动态语言互操作
dynamic
1.6 轻松编写异步代码
C# 5 的超级特性:异步函数。
Windows Forms中的线程有两条金科玉律:不能阻塞UI线程,并且不能在任何其他线程中访问UI元素(除非使用一些明确指定的方法)。
1.7 剖析.NET 平台
C#语言本身的特性、运行时的特性(可以认为运行时提供了程序运行的一个“引擎”)以及.NET框架库的特性。
1.7.1 C#语言
C#语言是由它的规范定义的。C#规范描述了C#源代码的格式,其中包括语法和行为。
C#编译器除了可以以IL (Intermediate Language ,中间语言)形式输出外,还可以以其他合法形式输出。
1.7.2 运行时
(Common Language Infrastructure ,公共语言基础设施)
CLI的运行时部分称为CLR (公共语言运行时)
1.7.3 框架库
.NET 中的框架库主要是以IL 的形式构建的,只有在必要时才使用本地代码。
.NET一词是指微软公司提供的运行时和库的组合,其中也包含C#和VB.NET编译器。
浙公网安备 33010602011771号