(P13) 在很大程度上,C# 2 更像是对 C# 1 的各种不足之处的修修补补,所以并没有一鸣惊人。而 C# 3 中几乎所有特性都是为了构建 LINQ,并且其结果也十分特别;
(P24)
为了让委托做某事,必须满足4个条件:
—— 声明委托类型;
—— 必须有一个方法包含了要执行的代码;
—— 必须创建一个委托实例;
—— 必须调用(invoke)委托实例;
(P30) 事件不是委托实例 —— 只是成对的 add/remove 方法 (类似于属性的 取值方法/赋值方法);
(P37)
数组类型是引用类型,即使元素类型是值类型(所以 int[] 仍是引用类型,即使 int 是值类型);
接口类型 (使用 interface 来声明) 是引用类型,但可由值类型实现;
(P38)
变量的值是在它声明时的位置存储的,局部变量的值总是存储在栈 (stack) 中,实例变量的值总是存储在实例本身存储的地方。引用类型实例 (对象) 总是存储在堆 (heap) 中,静态变量也是;
值类型不可以派生出其他类型;
(P40) 当你调用类型变量值的 GetType() 方法时总是伴随着装箱过程,因为它不能被重载。如果处理未装箱形式的变量,你应该已经知道了具体类型,因此使用 typeof 替代即可;
(P41)
引用类型的对象总是在堆上,值类型的值既可能在栈上,也可能在堆上,具体取决于上下文;
引用类型作为方法参数使用时,参数默认是以“值传递”方式来传递的 —— 但值本身是一个引用;
值类型的值会在需要引用类型的行为时被装箱;拆箱则是相反的过程;
(P47) 所谓“函数化”的编程风格,是指鼓励开发者更多地利用委托。匿名方法和Lambda表达式的引入,使委托变得易于创建和使用;
(P48) 从根本上说,泛型实现了类型和方法的“参数化”,就像在普通的方法调用中,经常要用参数来告诉它们使用什么值。同样,泛型类型和方法也可以让参数告诉它们使用什么类型;
(P52) 未绑定泛型类型是已构造类型的蓝图,已构造类型是实际的对象的蓝图,正是因为存在这个关系,所以才有“额外的抽象层”一说;
(P53) 其实 C# 语言规范已经说得很清楚,凡是不是“开放类型”的类型,就是“封闭类型”。凡是涉及类型参数的类型,就是“开放类型”;
(P55)
T 是在整个类的范围内使用的类型参数;
紧跟在方法名后面尖括号中的类型参数,是泛型方法的类型参数;
(P57)
不能因为一个方法是泛型的,就意味着它必须是泛型类型的一部分;
调用泛型方法时,使用和前面见到的一样的语法来指定参数类型;
(P58)
约束要放到泛型方法或泛型类型声明的末尾,并由上下文关键字 where 来引入;
引用类型约束表示成 T : class 必须是为类型参数指定的第一个约束;
构造函数类型约束表示成 T : new() 必须是所有类型参数的最后一个约束;
(P62)
每个类型参数的约束列表都要单独用一个 where 引入;
类型推断只适用于泛型方法,不适用于泛型类型;
(P74) 实现接口所规定的方法或属性时,附加接口名作为前缀,即称为“显式接口实现”;
(P78) 数组协变性 —— 引用类型的一个数组可以被视为它的基类型的一个数组,或者被视为它所实现的任何接口的一个数组;
(P141) 在常规的方法中,return 语句具有两个作用:第一,给调用者提供返回值;第二,终止方法的执行,在退出的时候执行合适的 finally 代码块;
(P194)
LINQ 的基本功能就是创建操作管道,以及这些操作需要的任何状态;
LINQ to Objects 处理的是同一个进程中的数据序列;
(P196)
Lambda 表达式最冗长的形式是 —— ( 显式类型参数列表 ) => {语句}
Lanbda 表达式快捷语法形式:
( 显式类型参数列表 ) => 表达式
( 隐式类型参数列表 ) => 表达式
参数名 => 表达式