C# variable length args, which is better and why: __arglist, params array or Dictionary<T,K>?

14,483

Solution 1

I would certainly never use __arglist, since it's undocumented and nobody knows what it means in any case.

I'd also avoid variable-length argument lists for as long as possible, and instead rework my design to understand what is truly variable, and to model that variability in a less platform-dependant manner.

Solution 2

C# 4 will have a better mechanism for this; 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);
}

Solution 3

In general, you are probably better off avoiding undocumented features of the language - for several reasons.

  • They are more likely to change then the established, documented features
  • They may have side-effects and implications that are not obvious in their usage
  • Other developers will not be familiar with them and will have a harder time maintaining your code
  • Refactoring tools (like VS itself or Resharper) are unlikely to be able to recognize them
  • They take away clarity from the intent of your code
  • There are language-supported alternatives to most of them

In the specific case of the __arglist, you can achieve the same capabilities with the language supported params keyword, which allows you to create type-safe variable argument lists for methods in C#. As a practice, though, I would be careful using it as it can obfuscate your code if used inpropertly - good use cases (like those in string.Format() which accepts variable arguments) - are less frequent than you would think.

Solution 4

It depends on the case. I've used params in cases where I have a variable number of arguments and it significantly adds to the readability of the calling code.

For example, I have a class that represents a TIFF document and allows access to a collection of pages which can be reordered and interspersed with other TIFF documents. Since one of the most common tasks our customers want is the ability to easily combine multiple TIFF documents into a single, we also provide the following two utility methods:

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

which in usage make the client code feel really nice:

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

Solution 5

I would prefer to not use any of the three techniques described here. I would instead design a value object that has strong types wherever possible, and possibly even nullable types. If push comes to shove you can create a generics-typed value object too.

There's just all so much code smell in this way of coding for me. A variable length collection of object ? Wouldn't pass unnoticed in my code review.

Edit: And if it DID pass my code review the parameter would in all likelyhood be an IEnumerable instance and none of the three suggestions items. IEnumerable is the leanest thing that could encapsulate my needs.

Share:
14,483
mkelley33
Author by

mkelley33

Me: Web Developer and Natural-Born World Shaker. Code: JavaScript, React, Node.js Likes: butterflies, birds, documentaries, sudoku, go, guitar, ukelele, synthesizers, cinema, collecting stamps, comic books, and disc golf Philosophy: Do it! - as simple as you can, just what is essential to pass it forward. from http://smallactsmanifesto.org/

Updated on June 04, 2022

Comments

  • mkelley33
    mkelley33 about 2 years

    I recently read the following overflow post: Hidden Features of C#

    One of the features pointed out was the arglist. Why would one choose this or the alternatives as a means of using a variable length argument list to a method? Also, note that I would probably not use this kind of construct in my code unless a corner case warranted doing so. This is more of a question of semantics than whether it is even practical or prudent to even use variable length arguments. So does anyone know which is better and why?

     [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);
     }
    
  • mkelley33
    mkelley33 about 15 years
    Thanks for the input. I didn't know it was undocumented. I appreciate your pointing that out. Certainly a good reason to be wary. Do know the differences in state/behavior between the 3 types (__arglist, params[] or Dictionary<string,object>)?
  • mkelley33
    mkelley33 about 15 years
    I totally agree with you, but this is simply a question pertaining to the pros and cons within the narrow context of the three types.
  • mkelley33
    mkelley33 about 15 years
    Hahaha, ok so I see where you stand on that one. I was just curious as to when one would be preferred over the other. I completely clear on their types. I looking for an explanation a little more in depth. I appreciate your criticism of using any of them. I agree 100%, but sometimes we interact with others, engaging in poor design, gritting our teeth and hoping for the best!
  • mkelley33
    mkelley33 about 15 years
    Thanks for the example. How is this more beneficial than using the __arglist, Dictionary<K,V> or even IEnumerable? How does it add to the readability? For example, what would you consider less readable? On what does your choice depend?
  • plinth
    plinth about 15 years
    Sure - C# isn't really good at making dynamic lists without heavy use of new (new Foo[] { new Foo(a), new Foo(b) }). Params strips one level of new out, removes some syntactic clutter, and in this example feels good across the use case. IEnumerable is better when the list of things needs to be built and manipulated programatically first (ie add, remove, sort). Dictionary<> is better for non homogeonous paramaterization, but it's distasteful to me. __arglist is right out.
  • GregRos
    GregRos almost 9 years
    Using a dictionary or params is poor design? What?
  • John Saunders
    John Saunders almost 9 years
    @GreĝRos I said "often" a sign of poor design. Not "always" a sign of poor design.
  • GregRos
    GregRos almost 9 years
    I still don't understand how using either can be any indication of bad design.
  • John Saunders
    John Saunders almost 9 years
    @gre I meant that frequently this is a bad sign, as it frequently indicates that the API is not well thought out.