在深入探讨这些特性在接口中的应用之前,先简要介绍这些特性。实际上,这些特性并非.NET 4的一部分,而是C#4.0引入的,因此在使用Visual Studio 2010时,即使在.NETFramework 3.5、3.0甚至2.0中也能使用这些特性。
从.NET4开始,可以在调用方法时明确指定参数名称。这有助于提高代码的可读性,并且调用者不需要记住参数的顺序。以下是一个C#中的方法示例:
public void Display(int x, int y, int z) {
// 方法实现
}
使用命名参数,可以按任意顺序传递参数。或者,可以在命名参数之前传递位置参数。需要注意的是,命名参数不能跟在位置参数之后,同时在混合使用位置参数和命名参数时,不能改变顺序。必须按照位置参数的位置传递。查看上面的代码,并查看最后两个调用(调用4和调用5)。在调用4中,没有按照正确的顺序传递位置参数。而在调用5中,命名参数后面跟着位置参数,这是不允许的,这两种方法调用都会在编译时出错。
.NET4引入的第二个特性是可选参数。现在可以为方法的参数指定默认值。在调用该方法时,可以选择传递该参数,或者直接使用默认参数。以下是一个修改后的GetBonus方法,将乘数2作为默认值的例子:
public double GetBonus(double salary, int yearsOfService, double multiplier = 2) {
// 方法实现
}
现在在调用这个方法时,可以传递这个参数,或者选择不传递。以下是调用这个方法的示例:
double bonus = GetBonus(salary: 50000, yearsOfService: 10);
double bonusWithMultiplier = GetBonus(salary: 50000, yearsOfService: 10, multiplier: 3);
这是一个很棒的特性,它可以帮助避免一些重载方法。乍一看,似乎编译器为生成了重载,但实际上并非如此。让看看使用ILDASM打开程序集并查看Main类的编译代码时IL代码是什么样子的。IL代码清楚地表明,编译器在没有为可选参数提供值的地方选择了默认值,并将这些值嵌入到调用代码中。
现在考虑一个场景,在接口中定义了GetBonus方法,并且也指定了默认参数。稍后,在类中实现了这个接口,并在那里也指定了默认参数。以下是代码示例。在接口ISalaryCalculator中定义了GetBonus方法,并为乘数和yearsOfService指定了默认值:
public interface ISalaryCalculator {
double GetBonus(double salary, int yearsOfService, double multiplier = 2);
}
在类SalaryCalculator中实现了这个方法。注意,在这里再次定义了默认参数,它们的值与在接口中定义的值不同:
public class SalaryCalculator : ISalaryCalculator {
public double GetBonus(double salary, int yearsOfService, double multiplier = 1.5) {
// 方法实现
}
}
SalaryCalculator calculator = new SalaryCalculator();
double bonus1 = calculator.GetBonus(salary: 50000, yearsOfService: 10);
double bonus2 = calculator.GetBonus(salary: 50000, yearsOfService: 10, multiplier: 3);
double bonus3 = ((ISalaryCalculator)calculator).GetBonus(salary: 50000, yearsOfService: 10);