tags:

views:

245

answers:

3

Simple. If I use:

public void Add(params int[] values)

Then I can use this as:

Add(1, 2, 3, 4);

But now I'm dealing with key-value pairs! I have a KeyValue class to link an integer to a string value. So I start with:

public void Add(params KeyValue[] values)

But I can't use this:

Add(1, "A", 2, "B", 3, "C", 4, "D");

Instead, I'm forced to use:

Add(new KeyValue(1, "A"), new KeyValue(2, "B"), new KeyValue(3, "C"), new KeyValue(4, "D"));

Ewww... Already I dislike this...

So, right now I use the Add function without the params modifier and just pass a pre-defined array to this function. Since it's just used for a quick initialization for a test, I'm not too much troubled about needing this additional code, although I want to keep the code simple to read. I would love to know a trick to use the method I can't use but is there any way to do this without using the "new KeyValue()" construction?

+14  A: 

If you accepted an IDictionary<int,string>, you could presumably use (in C# 3.0, at least):

Add(new Dictionary<int,string> {
     {1, "A"}, {2, "B"}, {3, "C"}, {4, "D"}
});

Any use?

Example Add:

static void Add(IDictionary<int, string> data) {
    foreach (var pair in data) {
        Console.WriteLine(pair.Key + " = " + pair.Value);
    }
}
Marc Gravell
Looks good! It does keep things in one line.
Workshop Alex
A: 

You could use something like the following with the obvious drawback that you loose strong typing.

 public void Add(params Object[] inputs)
 {
     Int32 numberPairs = inputs.Length / 2;

     KeyValue[] keyValues = new KeyValue[numberPairs];

     for (Int32 i = 0; i < numberPairs; i++)
     {
         Int32 key = (Int32)inputs[2 * i];
         String value = (String)inputs[2 * i + 1];

         keyvalues[i] = new KeyValue(key, value);
     }

     // Call the overloaded method accepting KeyValue[].
     this.Add(keyValues);
 }

 public void Add(params KeyValue[] values)
 {
     // Do work here.
 }

You should of cause add some error handling if the arguments are of incorrect type. Not that smart, but it will work.

Daniel Brückner
+2  A: 

You can modify your current class design, but you will need to add generics and use the IEnumerable interface.

    class KeyValue<TKey, TValue>
    {
        public KeyValue()
        {
        }
    }

    // 1. change: need to implement IEnumerable interface
    class KeyValueList<TKey, TValue> : IEnumerable<TKey>
    {
        // 2. prerequisite: parameterless constructor needed
        public KeyValueList()
        {
            // ...
        }

        // 3. need Add method to take advantage of
        // so called "collection initializers"
        public void Add(TKey key, TValue value)
        {
            // here you will need to initalize the
            // KeyValue object and add it
        }

        // need to implement IEnumerable<TKey> here!
    }

After these additions you can do the following:

    new KeyValueList<int, string>() { { 1, "A" }, { 2, "B" } };

The compiler will use the IEnumerable interface and the Add method to populate the KeyValueList. Note that it works for C# 3.0.

If you are using this for tests, these changes are not worth it. It's quite an effort and you change quite a lot of production code for tests.

Theo Lenndorff
Inheriting from `List<KeyValue<TKey, TValue>>` and adding the custom `Add` would be the easiest route here.
Marc Gravell
@Marc: Good idea. Haven't thought of that.
Theo Lenndorff