I need to create a Dictionary object as a member field
key = string
value = an instance of Action<T>
where T could be different per entry, e.g. long, int, string (a ValueType or a RefType)
However can't get the compiler to agree with me here.. To create a member field it seems to need a fixed T specification. I've passed my limit of struggle time before awareness that 'It shouldn't be this difficult'
Might be a generics noob mistake. Please enlighten..
The usage would be something like this
m_Map.Add("Key1",
new delegate(long l) {Console.Writeline("Woohoo !{0}", l.ToString();));
-
You can't, basically. How would the compiler know what type you were interested in for any particular entry?
You can't even explain a relationship of
Dictionary<Type, Action<T>>
where each dictionary entry has a key which is a type and an action which uses that type. Generics just doesn't support that relationship.If you will know the kind when you try to use it, you can just make it a
Dictionary<string, Delegate>
and cast the value when you fetch it. Alternatively, you could useAction<object>
and live with the boxing and cast you'll end up with.Note that to use anonymous methods or lambda expressions with just
Delegate
, you'll need to cast - or write a handy conversion method:public static Delegate ConvertAction<T>(Action<T> action) { return action; }
That way you can write:
Delegate dlg = ConvertAction((long x) => Console.WriteLine("Got {0}", x));
or in the dictionary context:
var dict = new Dictionary<string, Delegate>(); dict["Key1"] = ConvertAction((long x) => Console.WriteLine("Got {0}", x));
You'll still need to cast to the right type when you fetch the value out of the dictionary again though...
A different tack...
Instead of exposing a dictionary directly, you could encapsulate the dictionary in your own type, and have a generic
Add
method:public void Add<T>(string key, Action<T> action)
So it would still be a
Dictionary<string, Delegate>
behind the scenes, but your type would make sure that it only contained values which were delegates taking a single argument.Gishu : Tried that however get a compile-error: "Can't cast anonymous method to type Delegate"...Jon Skeet : See the edit I was writing while you commented :)Gishu : The only thing that I'm trying to enforce here is that the value should be a method that takes one parameter.Jon Skeet : Edited to account for this. (See the bottom.)Gishu : I ended doing a variation of what you too proposed.. worked. Just needed your tip of having to jump via an extra method to convert the Actionto a Delegate. Thanks -
With different
T
per entry, perhaps standardise atAction<object>
, and cast inside the actual actions?static void Main() { var m_Map = new Dictionary<string, Action<object>>(); m_Map.Add("Key1", obj => Console.WriteLine("Woohoo !{0}", obj)); m_Map.Add("Key2", obj => SomeMethod((int)obj)); m_Map["Key1"](123); m_Map["Key2"](123); } static void SomeMethod(int i) { Console.WriteLine("SomeMethod: {0}", i); }
Gishu : and box-unbox my value-types in these generic times.. Sacrilege! :) I must confess that I did think of that in one of my weaker moments whilst I was struggling to get this to work.Gishu : +1 for making me benchmark :) [.03 seconds. GC Collections = 3 for Action
0 comments:
Post a Comment