Dictionary of generic lists or varying types
I want to have a Dictionary that maps strings to generic lists of varying types. i.e. in the following form:
Key Value string List<T> string List<U> string List<V> string List<U> ...
Currently I'm using a Dictionary<string, ILis开发者_JAVA百科t>
and then extracted the strongly typed list from each dictionary KeyValuePair<string, IList> pair
entry as follows:
Type layerType = pair.Value.GetType().GetGenericArguments()[0];
List<layerType> objectsClicked = pair.Value as List<layerType>;
Is there a nicer way to do this?
[Edit]
As has been noted, the above doesn't compile, apologies - that's what you get when you ask a question while you're still working on somethings.
Some more explanation. I'm making a basic spatial data viewer. The final view consists of a group of Layer<T>
s. Each layer provides a delegate to render its type (given an offset and scale) and a way to check which of its objects are in the current window. For hit testing, I would like a List for each Layer of which objects have been hit. That list would be a List<Point>
for a Point
layer, etc... The grouping of the hits from all the Layer<T>
s would then be a collection of strongly typed lists.
How about Dictionary<string, dynamic>
assuming you're on C# 4
Dictionary<string, dynamic> Dict = new Dictionary<string, dynamic>();
Dict.Add("int", new List<int>());
Dict.Add("string", new List<string>());
Dict["int"].Add(12);
Dict["string"].Add("str");
foreach (KeyValuePair<string, dynamic> pair in Dict) {
Type T = pair.Value.GetType();
Console.WriteLine(T.GetGenericArguments()[0].ToString());
}
That prints out
System.Int32
System.String
Is that what you're looking for?
I am going to take a middleground between Euphoric and Adam, you should make use of both IList
and dynamic
. This is what I think is more correct:
var dict = new Dictionary<string, IList>();
dict.Add("u", new List<U>());
dict.Add("v", new List<V>());
// in case of members you know they exist on an IList
dict["u"].Add(new U());
dict["v"].Add(new V());
// in case you know what you are going to get back, in which case you should cast
var uProperty = (dict["u"][0] as U).UProperty
var vProperty = (dict["v"][0] as V).VProperty
// in case your're not sure of
(dict[someKey] as dynamic)[someIndex].SomeMember...;
All these are much simpler than relying on reflection. The basic idea is declare the dictionary value type as IList
to make your intentions clearer up front, while make use of dynamic
to ease the reflection monstrosity and make code shorter.
Using Dictionary<string, IList>
is possibly only solution. But your piece of code is wrong, you cant use generics like that. You cant create type dynamicaly like this.
The general problem with your need is that it is not compatible with strong-typed language like C#. In strong-typed language you must know what type is type EXACTLY. But thi cant be done using normal means. Also your understanding of generics is wrong. Its only compile-time extension to the type.
And general idea: In your case, using some kind OOP hiearchy of types that you save in those lists. This will be much better and safer idea and wont make everyone who looks at your code rip his hair out.
I actually think the cleaner approach is to create a wrapper for your dictionary:
public class GlobalStore
{
private readonly IDictionary<Type, IEnumerable> _globalStore;
public GlobalStore()
{
_globalStore = new ConcurrentDictionary<Type, IEnumerable>();
}
public IEnumerable<T> GetFromCache<T>()
where T : class
{
return (IEnumerable<T>) _globalStore[typeof(T)];
}
public void SetCache<T>(IEnumerable<T> cache)
where T : class
{
_globalStore[typeof(T)] = cache;
}
}
Here's a test for it:
[TestClass]
public class GlobalStoreTest
{
[TestMethod]
public void GlobalStore_Test()
{
//Arrange
var globalStore = new GlobalStore();
globalStore.SetCache(new List<ClientModel>
{
new ClientModel
{
ClientId = 1,
ClientName = "Client1"
},
new ClientModel
{
ClientId = 2,
ClientName = "Client2"
}
});
//Act
var clients = globalStore.GetFromCache<ClientModel>();
//Assert
Assert.AreEqual(2, clients.Count());
}
}
精彩评论