C#变长args,这更好,为什么:__ arglist,params数组或Dictionary ?

我最近阅读了以下溢出post: C#的隐藏function

其中一个特征是arglist。 为什么选择这个或替代方法作为对方法使用可变长度参数列表的方法? 另外,请注意我可能不会在我的代码中使用这种构造,除非角落案例需要这样做。 这更像是一个语义问题,而不是甚至使用可变长度参数是否实际或谨慎。 那么有谁知道哪个更好,为什么?

[Test] public void CanHandleVariableLengthArgs() { TakeVariableLengthArgs(__arglist(new StringBuilder(), 12)); object[] arr = { new StringBuilder() }; TakeVariableLengthArgs2(arr); TakeVariableLengthArgs3( new Dictionary { { "key", new StringBuilder() } }); } public void TakeVariableLengthArgs(__arglist) { var args = new ArgIterator(__arglist); var a = (StringBuilder)TypedReference.ToObject(args.GetNextArg()); a.Append(1); } public void TakeVariableLengthArgs2(params object[] args) { var a = (StringBuilder)args[0]; a.Append(1); } public void TakeVariableLengthArgs3(Dictionary args) { var a = (StringBuilder)args["StringBuilder"]; a.Append(1); } 

我肯定不会使用__arglist,因为它没有文档,没有人知道它在任何情况下意味着什么。

我也尽可能地避免使用可变长度的参数列表,而是重新设计我的设计以了解真正的变量,并以较少的平台依赖方式对变量进行建模。

C#4将有更好的机制; 命名和可选参数 :

 static void Main(string[] args) { // The method can be called in the normal way, by using positional arguments. Console.WriteLine(CalculateBMI(123, 64)); // Named arguments can be supplied for the parameters in either order. Console.WriteLine(CalculateBMI(weight: 123, height: 64)); Console.WriteLine(CalculateBMI(height: 64, weight: 123)); // Positional arguments cannot follow named arguments. // The following statement causes a compiler error. //Console.WriteLine(CalculateBMI(weight: 123, 64)); // Named arguments can follow positional arguments. Console.WriteLine(CalculateBMI(123, height: 64)); } static int CalculateBMI(int weight, int height) { return (weight * 703) / (height * height); } 

这取决于具体情况。 我在使用可变数量的参数的情况下使用了params,它显着增加了调用代码的可读性。

例如,我有一个表示TIFF文档的类,并允许访问可以重新排序并与其他TIFF文档交叉的页面集合。 由于客户需要的最常见任务之一是能够轻松地将多个TIFF文档合并为一个,我们还提供以下两种实用方法:

 public static void Combine(Stream output, params Stream[] sources) { /* ... */ } public static void Combine(Stream output, params string[] sourceFiles) { /* ... */ } 

在使用中使客户端代码感觉非常好:

 using (FileStream output = new FileStream(outputPath, FileMode.Create)) { TiffDocument.Combine(output, tpsCoverSheetPath, mainDocumentPath, tpsTrailerPath); } 

一般来说,最好避免使用该语言的无证function – 原因有几个。

  • 他们更有可能改变已建立的记录function
  • 它们可能具有副作用和影响,这些副作用和影响在其使用中并不明显
  • 其他开发人员将不熟悉它们,并且将难以维护您的代码
  • 重构工具(如VS本身或Resharper )不太可能识别它们
  • 它们消除了代码意图的清晰度
  • 大多数人都有语言支持的替代方案

在__arglist的特定情况下,您可以使用支持语言的params关键字实现相同的function,这允许您为C#中的方法创建类型安全的变量参数列表。 但是,作为一种惯例,我会小心使用它,因为如果在属性中使用它可能会混淆你的代码 – 好的用例(比如接受变量参数的string.Format()中的那些) – 比你想象的要少。

我宁愿不使用这里描述的三种技术中的任何一种。 我会设计一个尽可能具有强类型的值对象,甚至可以为可空的类型。 如果push推进,你也可以创建一个generics类型的值对象。

这种编码方式对我来说只有很多代码味道。 一个可变长度对象集合? 在我的代码审查中不会被忽视。

编辑 :如果它DID通过我的代码审查,参数将在所有可能性是一个IEnumerable实例,并没有三个建议项目。 IEnumerable是最简洁的东西,可以封装我的需求。