C#变长args,这更好,为什么:__ arglist,params数组或字典<t,k>?</t,k>

时间:2009-05-26 13:09:42

标签: c# c#-3.0 c#-2.0

我最近阅读了以下溢出帖子: Hidden Features of C#

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

 [Test]
 public void CanHandleVariableLengthArgs()
 {
     TakeVariableLengthArgs(__arglist(new StringBuilder(), 12));

     object[] arr = { new StringBuilder() };
     TakeVariableLengthArgs2(arr);

     TakeVariableLengthArgs3(
         new Dictionary<string, object> 
         { { "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<string, object> args)
 {
      var a = (StringBuilder)args["StringBuilder"];
      a.Append(1);
 }

5 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:4)

C#4将有更好的机制; named and optional arguments

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);
}

答案 2 :(得分:3)

这取决于具体情况。我使用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);
}

答案 3 :(得分:3)

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

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

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

答案 4 :(得分:0)

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

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

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