命名参数和默认参数都是很简单但是很实用的功能,可谓是千呼万唤始出来,在C#4.0里终于见到它们的身影。先看看命名参数的例子:
static void Main(string[] args)
{
GetData(useCache: true);
}
GetData(useCache: true)相当于GetData(true)。相较以前的写法,命名参数可以大大提高代码的可读性,读代码的人可以清晰地知道这个bool参数指的是是否使用cache。(再此之前我很不喜欢定义接口的时候使用bool型的参数,就因为调用它的代码可读性很差)
因为被调用方法通过名字得到参数,因此顺序是无关的,也就是说当用命名参数的时候,调用的顺序和定义的顺序可以不一致,比如这个例子:
static void Main(string[] args)
{
GetData(useCache: true, name: "anders");
}
private static int GetData(string name, bool useCache)
{
return 0;
}
再看看默认参数,和C++的语法一样,用=value来表示默认参数:
private static int GetData(string name, bool useCache = true)
{
return 0;
}
写到这里我不由得想到了那个经典的C++题目:当一个虚拟函数有默认参数,被一个基类的指针调用时,使用的参数是?用C#的表述就是下面这段代码:
class Program
{
public static void Main()
{
Base obj = new MyClass();
Console.WriteLine(obj.GetName());
Console.WriteLine(((MyClass)obj).GetName());
MyClass myObj = new MyClass();
Console.WriteLine(myObj.GetName());
}
}
class Base
{
public virtual string GetName(string baseName = "base")
{
return baseName;
}
}
class MyClass : Base
{
public override string GetName(string baseName = "myClass")
{
return baseName;
}
}
有趣的是,虽然实现上和C++全然不同,两者的行为是完全一样的:既谁调用,用谁的参数。如果是用Base调用,虽然对象是MyClass类型,执行的也是MyClass.GetName(), 但默认参数使用的是Base.GetName()的。这是因为C#的实现是通过给参数加属性,而属性这种东西是相对“静态”的,不会被virtual掉,那么也就自然是谁调用,就用谁的属性了。