C# 4.0 的主题就是动态编程 (Dynamic Programming) 。虽然 C# 仍然是一种静态语言,但是对象的意义开始变得越来越“动态”。它们的结构和行为无法通过静态类型来捕获,或者至少编译器在编译程序时无法得知对象的结构和行为。
一、 dynamic 关键字
C# 引入了一种新的静态类型” dynamic ”,当你拥有了一个 dynamic 类型的对象后,你“对它做的事情”只会在运行时进行解析 , 不需要再进行类型转换。
原来要写: object obj = GetObject();obj.GetType().InvokeMember(“CallSomeFunc”, …., new object[] { 1 }); // 需要通过反射才能动态调用一个方法
现在只需: dynamic obj = GetObject();obj.CallSomeFunc(1);// 直接输入方法名,运行时将会动态调用
二、可选参数 / 命名参数
public StreamReader OpenTextFile(string path,Encoding encoding = null ,int bufferSize = 1024);
命名参数必须在最后使用: OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 4096);
顺序不限: OpenTextFile(bufferSize: 4096, path: "foo.txt", detectEncoding: false);
三、特定于 COM 的互操作性
在 C# 中在调用 COM 对象如 office 对象时,经常需要写一堆不必要的参数: object fileName = "Test.docx";object missing = System.Reflection.Missing.Value;
doc.SaveAs(ref fileName,ref missing, ref missing, ref missing,ref missing, ref missing, ref missing);4.0 中就可以直接写成: doc.SaveAs("Test.docx");
现在可以直接赋值 :excel.Cells[1, 1].Value = "Hello";
而不用写 ((Excel.Range)excel.Cells[1, 1]).Value2= "Hello";
四、通过委托成员来实现接口
public class Foo : IList<string> { private List<string> _Collection implements IList<string>; public Foo() { _Collection = new List<string>(); }}
在委托实现接口之余,我们也应当可以自由地重写某些方法如下:
public int IList.Add(string value) { if (!_Collection.Contains(value)) _Collection.Add(value); }
五、安全的 null 延迟赋值操作符
我很想看到一种安全地访问一个值为 null 的对象的属性的表达式,表达式可能形如 Object.Property.Property.Value
比如我要访问 Customer?.FirstName ,但是 Customer 是 null ,此时 Customer?.FirstName 会返回 null 而不是抛出个 NullReferenceException
六、一些 Duck-typing 或 Structural Subtyping 支持
在 .NET 框架中,一部分控件实现了一个叫 ReadOnly 的属性,比如 TextBox, DataGrid, NumericUpDown; 现在我们建一个叫 IReadOnlyRestricable 的接口。
public interface IReadOnlyRestricable { bool ReadOnly { get; set; } }
然后我们要遍历所有的控件,找出有 ReadOnly 属性的控件并把此属性设为 true( 注:这些控件本身没有实现 IReadOnlyRestricable) ,在 ducktyping 下我们可以把控件通过类型转换为 IReadOnlyRestricable ,就像下面代码一样,这样我们就不需要通过反射去定位 ReadOnly 属性了:
foreach (Control c in f.Controls) { IReadOnlyRestricable editable = c as IReadOnlyRestricable; if (editable != null) editable.ReadOnly = true; }
七、变性 ( 协变性和逆变性 )
过去, IEnumerable<string> 并不是 IEnumerable<object> ,现在它是了。
在 C# 中,下面的类型转换是非法的:
IList<string> strings = new List<string>();IList<object> objects = strings;
因为你有可能会这样做,而编译器的静态检查无法查出错误: objects[0] = 5; string s = strings[0];
4.0 中在声明泛型的接口及委托时可以加 in 及 out 关键字,如:
public interface IEnumerable<out T> : IEnumerable {IEnumerator<T> GetEnumerator();}
out 关键字的意思是说 IEnumerable<T> 中 T 只会被用在输出中,值不会被改变。这样将 IEnumerable<string> 转为 IEnumerable<object> 类型就是安全的。
in 的意思正好相反,是说 IComparer<T> 中的 T 只会被用在输入中,这样就可以将 IComparer<object> 安全的转为 IComparer<string> 类型。前者被称为协变, 后者就是逆变。