2012-02-07 4 views
3

У меня есть следующий код:Итерация через Generic словарь бросает исключение

private Dictionary<int, Entity> m_allEntities; 
private Dictionary<Entity, List<IComponent>> m_entityComponents; 

public Dictionary<int, T> GetComponentType<T>() where T: IComponent 
{ 
    Dictionary<int, T> components = new Dictionary<int, T>(); 

    foreach (KeyValuePair<int, Entity> pair in m_allEntities) 
    { 
     foreach (T t in m_entityComponents[m_allEntities[pair.Key]]) 
     { 
      components.Add(pair.Key, t); 
     } 
    } 

    return components; 
} 

m_allEntities = Словарь всех лиц с Key: их ID и значение: объект Entity. m_entityComponents = Словарь всех объектов и их список компонентов с помощью Key: Entity object и Value: это список компонентов.

У меня есть несколько различных классов, реализующих интерфейс IComponents. Предполагается, что должна выполняться функция GetComponentType() - это цикл через все сущности и создание словаря идентификаторов объектов и компонентов определенного типа.

Например: если я хочу, чтобы получить список всех лиц, которые имеют расположение компонентов, то я хотел бы использовать:

entityManager.GetComponentType<Location>(); 

Проблема, что я бегу в это второй цикл, потому что Безразлично» t, похоже, фильтрует мой словарь. Вместо этого он пытается включить все компоненты в словаре в тип местоположения, который, конечно же, выдает исключение. Как я могу изменить этот код, чтобы он делал то, что я хочу?

ответ

2

Вы можете использовать .OfType<T> метод:

foreach (T t in m_entityComponents[m_allEntities[pair.Key]].OfType<T>()) 

для фильтрации элементов, соответствующих Вашему общего типа.

+0

Просто попробовал это и .OfType () для меня не является методом. Нужно ли включать дополнительный оператор использования для этой функции или что-то еще? – Kittoes0124

+0

@ Китто: да, вам нужно пространство имен LINQ. Просто добавьте 'using System.Linq;' –

+0

Я так много думал, должен был просто попробовать добавить LINQ прежде, чем спросить. Мне действительно нравится это решение, потому что мне не нужно что-то делать. Решение ChaosPandion выше также получилось достаточно хорошо. Какой из двух вариантов «безопаснее» и есть ли разница в производительности между этими двумя? – Kittoes0124

4

Если ваша коллекция имеет разные типы, вам необходимо протестировать подходящий тип.

public Dictionary<int, T> GetComponentType<T>() where T: IComponent 
{ 
    Dictionary<int, T> components = new Dictionary<int, T>(); 

    foreach (KeyValuePair<int, Entity> pair in m_allEntities) 
    { 
     foreach (IComponent c in m_entityComponents[m_allEntities[pair.Key]]) 
     { 
      if (c is T) 
       components.Add(pair.Key, (T)c); 
     } 
    } 

    return components; 
} 
+0

Спасибо, я просто проверил это изменение, и оно даже не будет скомпилировано. Неверная строка: var t = c как T ;. Ошибка: «Параметр типа« T »не может использоваться с оператором« as », поскольку он не имеет ограничения типа класса или ограничения класса.» – Kittoes0124

+0

@ Kittoes - Я проигнорирую тот факт, что ошибка очень конкретна. Однако, если вы посмотрите на мои изменения, они устраняют необходимость ограничения класса. – ChaosPandion

+0

Еще раз большое спасибо. Это закончилось тем, что работала неплохо. jimmy_keen также разместил решение ниже, которое мне очень понравилось. Который вы порекомендовали бы использовать (поскольку они оба делают именно то, что мне нужно)? – Kittoes0124