Словарь общих списков или разных типов
Я хочу иметь словарь, который отображает строки в общие списки разных типов. то есть в следующем виде:
Key Value
string List<T>
string List<U>
string List<V>
string List<U>
...
В настоящее время я использую Dictionary<string, IList>
, а затем извлекаю строго типизированный список из каждой словарной статьи KeyValuePair<string, IList> pair
следующим образом:
Type layerType = pair.Value.GetType().GetGenericArguments()[0];
List<layerType> objectsClicked = pair.Value as List<layerType>;
Есть ли лучший способ сделать это?
[Изменить]
Как уже отмечалось, вышесказанное не компилируется, извинения - это то, что вы получаете, когда задаете вопрос, пока вы все еще работаете над чем-то.
Еще несколько объяснений. Я делаю основной просмотрщик пространственных данных. Окончательный вид состоит из группы Layer<T>
s. Каждый слой предоставляет делегату возможность отображать его тип (с учетом смещения и масштаба) и способ проверить, какие из его объектов находятся в текущем окне. Для тестирования попадания я хотел бы получить список для каждого слоя, из которого были удалены объекты. Этот список будет List<Point>
для слоя Point
и т.д.... Группировка обращений от всех Layer<T>
будет тогда набором строго типизированных списков.
Ответы
Ответ 1
Как насчет Dictionary<string, dynamic>
при условии, что вы находитесь на С# 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());
}
Это выводит
System.Int32
System.String
Это то, что вы ищете?
Ответ 2
Использование Dictionary<string, IList>
- возможно только решение. Но ваш код неправильный, вы не можете использовать такие дженерики. Вы не можете создать динамическую динамику типа.
Общая проблема с вашей потребностью заключается в том, что она несовместима с языком с сильным типом, подобным С#. В строго типизированном языке вы должны знать, какой тип типа ТОЧНО. Но это можно сделать обычными способами. Также ваше понимание дженериков неверно. Его единственное расширение времени компиляции для типа.
И общая идея. В вашем случае, используя какой-то вид ООП, поиск типов, которые вы сохраняете в этих списках. Это будет намного лучше и безопаснее, и не заставит всех, кто смотрит на ваш код, вырвать его волосы.
Ответ 3
Я собираюсь взять промежуточное звено между Эйфориком и Адамом, вы должны использовать как IList
, так и dynamic
. Это то, что я считаю более правильным:
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...;
Все это намного проще, чем полагаться на отражение. Основная идея - объявить тип значения словаря как IList
, чтобы сделать ваши намерения более ясными спереди, а использовать dynamic
, чтобы облегчить монтировку отражения и сделать код короче.
Ответ 4
Я действительно думаю, что более чистый подход - создать оболочку для вашего словаря:
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;
}
}
Вот тест для него:
[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());
}
}