Словарь общих списков или разных типов

17

Я хочу иметь словарь, который отображает строки в общие списки разных типов. то есть в следующем виде:

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> s будет тогда набором строго типизированных списков.

    
задан Matthew Finlay 18.02.2011 в 06:37
источник
  • Предоставленный образец кода не будет компилироваться. В любом случае, это действительно помогло бы, если бы вы могли сказать нам: а) что вы собираетесь делать со списком, как только вы его получите. B) какая большая проблема вы пытаетесь решить. –  Ani 18.02.2011 в 06:39
  • То, что у вас есть, не будет компилироваться. Вы не можете передать объект типа в качестве типичного параметра типа. Почему даже нужны дженерики, если вы не получаете доступ к списку строго типизированным способом? –  Josh 18.02.2011 в 06:41
  • Поскольку вы помещаете эти списки в один и тот же словарь, между ними должны быть некоторые общие основания (например, они имеют один и тот же базовый класс / интерфейс или что-то еще). Вы должны предоставить дополнительную информацию. –  Danny Chen 18.02.2011 в 07:09

4 ответа

35

Как насчет Dictionary<string, dynamic> при условии, что вы находитесь на 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());
}

Это выводит

  

System.Int32

     

System.String

Это то, что вы ищете?

    
ответ дан Adam Rackis 18.02.2011 в 06:41
источник
  • Я думаю, что его Словарь <string, IList> намного лучше. Не путайте его с динамикой. –  Euphoric 18.02.2011 в 06:47
  • Да, вы могли бы сделать это с помощью словаря <string, object>, но тогда вам придется делать бросок каждый раз, когда вы обращаетесь к чему-то внутри своего Словаря, чтобы манипулировать списком. Множество людей зарабатывают на жизнь динамическими языками, я не думаю, что кто-нибудь будет убивать кого-нибудь, чтобы использовать динамическую типизацию на C # время от времени, когда ситуация требует этого. Я думаю, что некоторые языковые пуристы должны немного успокоиться –  Adam Rackis 18.02.2011 в 06:54
  • @Adam - я дал вам преимущество, ваше решение в порядке, но Euphoric пока не определил родословные, но я бы не стал путать его с динамикой. –  Enigmativity 18.02.2011 в 06:56
  • Динамика служит гораздо больше, чем «классный фактор». Он позволяет использовать утиную печать, объекты «expando» и упрощенное отражение. Если вы когда-нибудь сделаете такой унизительный комментарий, я пошлю Эрика Липперта после вас ... –  Adam Rackis 18.02.2011 в 07:02
  • VINDICATION !! :-D –  Adam Rackis 20.02.2011 в 23:31
Показать остальные комментарии
2

Использование Dictionary<string, IList> возможно только решение. Но ваш код неправильный, вы не можете использовать такие дженерики. Вы не можете создать динамическую динамику типа.

Общая проблема с вашей потребностью заключается в том, что она несовместима с языком с сильным типом, подобным C #. В строго типизированном языке вы должны знать, какой тип типа ТОЧНО. Но это можно сделать обычными способами. Также ваше понимание дженериков неверно. Его единственное расширение времени компиляции для типа.

И общая идея . В вашем случае, используя какой-то вид ООП, поиск типов, которые вы сохраняете в этих списках. Это будет намного лучше и безопаснее, и не заставит всех, кто смотрит на ваш код, вырвать его волосы.

    
ответ дан Euphoric 18.02.2011 в 06:46
источник
  • Ситуации, подобные этому, когда вам нужна гибкость в системе типов, именно то, для чего была разработана динамика (среди прочего, как более легкое отражение). –  Adam Rackis 18.02.2011 в 06:50
2

Я собираюсь взять промежуточное звено между Эйфориком и Адамом, вы должны использовать как 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 , чтобы облегчить отражение и сделать код короче.

    
ответ дан nawfal 22.03.2016 в 06:43
источник
0

Я действительно думаю, что более чистый подход - создать оболочку для вашего словаря:

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());
    }
}
    
ответ дан ODawg G 07.05.2017 в 00:15
источник