已知问题
这里可能有一些限制或与你期望的结果不同。
- DLR允许从一个表示类的对象创建对象。然而,C#的当前实现还不具备支持这一功能的语法。
- 动态查找不能查找扩展方法。不论扩展方法是否依赖该调用的静态上下文(也就是出现了using语句),因为该上下文信息并不会作为有效载荷的一部分保留下来。
- 匿名函数(也就是lambda表达式)不能作为实参传递给动态方法调用。在不知道要转换成什么类型的情况下,编译器不能绑定(也就是“理解”)一个匿名函数。
这些限制导致的结果就是很难在动态对象上使用LINQ查询——
var result = collection.Select(e => e + 5);
dynamic collection = ...;
dynamic collection = ...;
如果Selected方法是个扩展方法,动态查找将找不到它。即便它是一个实例方法,上面的代码也无法编译,因为lambda表达式不能作为参数传递给动态操作。
在C# 4.0中没有计划解决这些限制。
命名参数和可选参数
命名参数和可选参数是两个截然不同的功能,但通常一起使用。在进行成员调用时,可以忽略可选参数;而命名参数的方式可以通过名称来提供一个参数,而无需依赖它在参数列表中出现的位置。
有些API——尤其是COM接口——如Office自动化API——确实本身就是通过命名参数和可选参数编写的。之前在C#中调用这些API非常痛苦,尤其有的时候需要多达30几个参数都必须显式传递,而其中大多数都具有合理的默认值,是可以忽略的。
即便是编写.NET中的API,你也会发现很多时候你在被迫为不同的参数组合方式编写一个方法的大量重载形式,以便给调用者提供最高的可用性。在这种情况下,可选参数就会成为一种非常有用的替代方式。
可选参数
为一个参数提供默认值就可以将其声明为可选的——
public void M(int x, int y = 5, int z = 7);
这里的y和z就是可选参数,在调用时可以忽略——
M(1, 2, 3); // ordinary call of M
M(1, 2); // omitting z – equivalent to M(1, 2, 7)
M(1); // omitting both y and z – equivalent to M(1, 5, 7)
M(1, 2); // omitting z – equivalent to M(1, 2, 7)
M(1); // omitting both y and z – equivalent to M(1, 5, 7)
命名的和可选的实参
C# 4.0不允许忽略逗号之间的实参,比如M(1,,3)。否则会导致大量不可读的、需要“数逗号”的代码。替代方式是任何参数都可以通过名字传递。因此如果在调用M时只希望忽略y,可以写——
- M(1, z: 3); // passing z by name
或
- M(x: 1, z: 3); // passing both x and z by name
甚至
- M(z: 3, x: 1); // reversing the order of arguments
这几种形式都是等价的,不过参数总是按照其出现的顺序进行求值,因此对于最后一个示例来说,3会在1之前求值。
可选参数和命名参数不仅可以用在方法调用中,还可以用在索引器和构造器中。