答:大多数的现代程序语言都为可选功能参数提供了某种支持,但是C#没有为此提供直接的支持,尽管VB.NET和.NET的属性系统都支持此功能。这是当前C#社区中正在争辩的一个话题之一。C#的开发组倾向于以下的立场:即使提供了,这个特性通常只是外面裹了糖衣的一个过载的方法。
如果你仔细考虑一下就会觉得他们的立场是有道理的。一个带有可选参数的函数实际上是两个不同的函数:如果没有可选参数,一个函数就会进行某种缺省的行为;如果提供了可选参数,另一个函数就会按照可选参数的值进行更加确定的行为。但是这并没有改变这样一个事实,那就是使用过载方法提供的对可选参数的支持还是让人感到很笨拙。它的确有效,但是你不得不写更多的代码,而且为支持你所有可选参数所需要的额外方法签名会败坏掉你的对象接口。让我们来看几个替代方法。
如果你看一下通用语言运行时(CLR)里找到的类,你就会发现有很多的方法都接收参数的变长表。System.Console.WriteLine方法就是一个例子。这个方法有一个过载声明,用以支持写给控制台的串的可换参数。例如这行代码:
Console.WriteLine(" jumped over .", "The cow", "the moon");
产生了以下的输出:
The cow jumped over the moon.
使用这样的方法,任何数量的可替换参数都可被指定,这就意味着传递给WriteLine方法的自变量的数量可以随不同的调用而改变。C#使用params关键字对这种行为提供支持,那么在函数自变量表里的数组类型前使用这个关键字将创建一个参数数组。你可以在实际工作中使用这个数组伪造可选参数。你可以在Listing A里实际运行一下这个例子。
你可以看到这个解决方案工作得非常好。OptionalStrings方法可以在不加参数的情况被合法调用,在这种情况下,参数数组args是空的,实际上,整个数组都是可选的。更进一步说,调用函数不用明确地将它送出的数组里的参数包装起来。由于参数数组是一种纯净的数组,所以被调用的函数可以很容易地决定自己可以接受多少参数。但是有些东西要提醒一下:
使用这样的方法,没有强制确定可以接受的自变量的数量。例如,如果在函数自身的运行时间内不编写代码确定OptionalStrings方法所能接受参数的最大数量,你就不能宣布此方法只能最多接受三个可选自变量。
类似的,也没有办法让数组确保类型。如果你需要在参数数组里支持多个类型,你就被限制在只能使用最小公分母的方法,通常是宣布参数数组为类型Object。
只有一个参数可以被标记为params,而且只能是方法自变量表的最后一个参数。
你不能使用这种方法指定一个可选的out(由检索来传递)参数。
另一个可能的解决方案是创建一个类,把一个方法能够接受的所有可能参数全都封装起来,再把这个类的实例传递给正在处理的方法。从面向对象的角度来看,这个方法很有效,解决了使用参数数组解决方案处理不了的问题,这你会在Listing B里看到。
为ParameterClass类创建一个缺省的、不带参数的构造器,我就可以给公共字段设定任何缺省的值,这就代表着OptionalObjects方法可能的参数。我刚刚超越了我感兴趣并希望提供值的任何字段,并把整个过对象都传递给了OptionalObjects。因为对象是由检索传递的,所以所有的变化都是针对ParameterClass字段的,而在OptionalOjects内部,方法是在其返回时反射的。实际上,整个对象都是一个out参数。
这种方法不仅为你的可选参数的难题提供了巧妙的解决方案,还在通过对象的形式传递自变量的同时,将不同的类隔离起来。使用这个方法,就可能给OptionalObjects加入额外的自变量,同时将混乱控制在最小。你所要做的就是简单地重新定义ParameterClass,使之能包含新字段。
以上所有的解决方案都是不是完美的,但是他们都能虚拟的支持你应用程序里的可选参数。既然从微软传来的消息表明未来仍不会内置对可选参数的支持,我们现在还是只能这样做。
欢迎评论或投稿