19

Possible Duplicate:
Custom Collection Initializers

I have a simple Pair class:

public class Pair<T1, T2>
    {
        public Pair(T1 value1, T2 value2)
        {
            Value1 = value1;
            Value2 = value2;
        }

        public T1 Value1 { get; set; }
        public T2 Value2 { get; set; }
    }

And would like to be able to define it like a Dictionary object, all inline like so:

var temp = new Pair<int, string>[]
        {
            {0, "bob"},
            {1, "phil"},
            {0, "nick"}
        };

But it is asking me to define a full new Pair(0, "bob") etc, how would I implement this?

As usual, thanks guys!

Community
  • 1
  • 1
Chris Surfleet
  • 2,462
  • 4
  • 28
  • 40
  • Good question! I edited your answer to use the correct terminology (collection initializer). This is usually accomplished on the collection side of things (it has to have an Add() method). In this case you're using an array so it doesn't quite work in the same way. But very interested to see if there are ways to make it work! – MattDavey Mar 05 '12 at 16:35
  • Not a fan of `KeyValuePair`? Or going for the applied knowledge? – Brad Christie Mar 05 '12 at 16:37

4 Answers4

24

To get the custom initialization to work like Dictionary you need to support two things. Your type needs to implement IEnumerable and have an appropriate Add method. You are initializing an Array, which doesn't have an Add method. For example

class PairList<T1, T2> : IEnumerable
{
    private List<Pair<T1, T2>> _list = new List<Pair<T1, T2>>();

    public void Add(T1 arg1, T2 arg2)
    {
        _list.Add(new Pair<T1, T2>(arg1, arg2));
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return _list.GetEnumerator();
    }
}

and then you can do

var temp = new PairList<int, string>
{
    {0, "bob"},
    {1, "phil"},
    {0, "nick"}
};
Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
  • Are you suggesting that `int[] nums = {1, 2, 3};` isn't valid C#? because it is... Surely the problem is that Pair doesn't have the Add method? – Chris Mar 05 '12 at 16:41
  • @Chris That isn't like dictionary. – Yuriy Faktorovich Mar 05 '12 at 16:42
  • Yeah, looking more I see where the problem is. I had thought that since the syntax works as in my comment that the problem was with the generation of the Pair object. On looking at more things (and attempting to write valid code to do this) I realised that the syntax as used by the original post is trying to call Add(1,"bob") on the array which is what you were saying doesn't exist. Sorry about that, I'll leave the comment for the next poor fool to think like me though. :) – Chris Mar 05 '12 at 16:46
  • @Chris I've added some sample code which shows how the Dictionary does this. The stupid thing it doesn't matter what the IEnumerable type is, just that it's there. – Yuriy Faktorovich Mar 05 '12 at 16:52
  • I'd actually just spent that time writing my own version. I think you can get a much nicer version by inheriting `List<...>` rather than just implementing `` since it gets you lots of other functionality (like being able to enumerate through it once you're done). – Chris Mar 05 '12 at 16:59
  • @Chris I generally stay away from inheriting from built collection types. In fact yours might be the first time I've seen it done in a useful and correct way. – Yuriy Faktorovich Mar 05 '12 at 17:02
  • I feel flattered. :) Is this just because it is so easy to mess things up when inheriting from built in objects like this or are there other insidious reasons? The main reason I went down that road is because when I was testing it I wanted to iterate through the list to make sure everything was in as it should be and it seemed to be wrong to be building enumerators and so on and so forth... – Chris Mar 05 '12 at 17:15
  • @Chris the reason is that most of them don't have any virtual members, I can't actually think of one that does. And since they don't have vitual members, in most cases whatever functionality you're adding will be overridden by just casting the instance to the base class. But in your case you're only adding a method to give yourself some syntax freedom, making the casting pointless. – Yuriy Faktorovich Mar 05 '12 at 17:22
  • That makes sense. I'll certainly keep that in mind if I ever get tempted by this in the future. :) – Chris Mar 05 '12 at 17:24
  • @RichK Thank you for correcting me. That makes more sense than IEnumerable. I take back my stupid comment. – Yuriy Faktorovich Mar 05 '12 at 17:28
  • Thanks guys this makes sense, and good discussion too! – Chris Surfleet Mar 06 '12 at 08:16
8

Why not use a class that inherits from Dictionary?

public class PairDictionary : Dictionary<int, string>
{
}

private static void Main(string[] args)
{
    var temp = new PairDictionary
    {
        {0, "bob"},
        {1, "phil"},
        {2, "nick"}
    };

    Console.ReadKey();
}

You could also create your own collection (I suspect it is the case because you have the same Value1 for two items, so T1 doesn't act as a key in your example) that do not inherit from Dictionary.

If you want to use the syntactic sugar of collection initializer, you would have to provide a Add method that takes 2 arguments (T1 and T2 which are int and string in your case).

public void Add(int value1, string value2)
{
}

See Custom Collection Initializers

Community
  • 1
  • 1
ken2k
  • 48,145
  • 10
  • 116
  • 176
5
public class Paircollection<T1, T2> : List<Pair<T1, T2>>
{
    public void Add(T1 value1, T2 value2)
    {
        Add(new Pair<T1, T2>(value1, value2));
    }
}

and then

var temp = new Paircollection<int, string>
{
    {0, "bob"},
    {1, "phil"},
    {0, "nick"}
};

will work. Essentially you're just creating a version of List<Pair<T1,T2>> that knows how to do the right Add things.

This is obviously expandable to any other class than Pair (in a way that the dictionary solutions aren't).

Thanks to Yuriy Faktorovich for helping me with my initial understanding and the linked question for pointing me in teh right direction.

IAbstract
  • 19,551
  • 15
  • 98
  • 146
Chris
  • 27,210
  • 6
  • 71
  • 92
0

The syntax you're looking for is not provided by the object that is being used with the dictionary, it is the dictionary collection itself. If you need to be able to use a collection initializer then you'll need to use an existing collection (like Dictionary) or implement a custom collection to house it.

Otherwise you're basically limited to:

var temp = new Pair<int, string>[]
    {
        new Pair(0, "bob"),
        new Pair(1, "phil"),
        new Pair(0, "nick")
    };
M.Babcock
  • 18,753
  • 6
  • 54
  • 84