tags:

views:

653

answers:

3

I'd like to create a Dictionary object, with string Keys, holding values which are of a generic type. I imagine that it would look something like this:

Dictionary<string, List<T>> d = new Dictionary<string, List<T>>();

And enable me to add the following:

d.Add("Numbers", new List<int>());
d.Add("Letters", new List<string>());

I know that I can do it for a list of strings, for example, using this syntax:

Dictionary<string, List<string>> d = new Dictionary<string, List<string>>();
d.Add("Key", new List<string>());

but I'd like to do it for a generic list if possible...

2 questions then:

  1. Is it possible?
  2. What's the syntax?

Many thanks,
Jon

+8  A: 

EDIT: Now I've reread the question...

You can't do this, but a custom collection would handle it to some extent. You'd basically have a generic Add method:

public void Add<T>(string key, List<T> list)

(The collection itself wouldn't be generic - unless you wanted to make the key type generic.)

You couldn't extract values from it in a strongly typed manner though, because the compiler won't know which type you've used for a particular key. If you make the key the type itself, you end with a slightly better situation, but one which still isn't supported by the existing collections. That's the situation my original answer was responding to.

EDIT: Original answer, when I hadn't quite read the question correctly, but which may be informative anyway...

No, you can't make one type argument depend on another, I'm afraid. It's just one of the things one might want to express in a generic type system but which .NET's constraints don't allow for. There are always going to be such problems, and the .NET designers chose to keep generics relatively simple.

However, you can write a collection to enforce it fairly easily. I have an example in a blog post which only keeps a single value, but it would be easy to extend that to use a list.

Jon Skeet
As usual nice solution jon
JoshBerke
Ah, I see the problem now - there's no way to do type inference on anything you extract from the collection. I guess that's the reason why it's not included as a feature. Thanks!
Jon Artus
A: 

Would something like this work?

public class GenericDictionary
{
    private Dictionary<string, object> _dict = new Dictionary<string, object>();

    public void Add<T>(string key, T value) where T : class
    {
        _dict.Add(key, value);
    }

    public T GetValue<T>(string key) where T : class
    {
        return _dict[key] as T;
    }
}

Basically it wraps all the casting behind the scenes for you.

JoshBerke
+2  A: 

I prefer this way of putting generic types into a collection:

interface IList
{
  void Add (object item);
}

class MyList<T> : List<T>, IList
{
  public void Add (object item)
  {
    base.Add ((T) item); // could put a type check here
  }
}

class Program
{
  static void Main (string [] args)
  {
    SortedDictionary<int, IList>
      dict = new SortedDictionary<int, IList> ();

    dict [0] = new MyList<int> ();
    dict [1] = new MyList<float> ();

    dict [0].Add (42);
    dict [1].Add ("Hello"); // Fails! Type cast exception.
  }
}

But you do lose the type checks at compile time.

Skizz

Skizz
Exactly what I was thinking: use a Dictionary<string, IList>.
Jim Mischel