开发者

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());
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜