#c# #list #generics
#c# #Список #общие
Вопрос:
У меня есть общий класс для всех менеджеров, которые есть в моей структуре. (Например, менеджеры для объектов, игровых сигналов, физики и частиц).
По сути, все они делают одно и то же. У них есть набор вещей, им нужно обновить эти вещи, и им нужно отобразить эти вещи (ну, не всем менеджерам нужно отображать .. но в любом случае). Итак, у меня есть общий базовый класс, который делает именно это. Я определяю, какие «вещи» он хранит.
public class GenericManager<T> where T : Updatable
И объекты в моей игре, такие как объекты / частицы / etc, наследуют возможность обновления, и мы уходим.
public class EntityManager : GenericManager<Entity>
и, конечно, сущность
public class Entity: Updatable
Теперь мне интересно, как бы я поместил всех этих менеджеров в список менеджеров. Мне нужен способ сохранить их все, выполнить итерацию по ним и обновить их в еще одном менеджере (я полагаю).
PS Возможно, это не идеальный способ справиться с тем, что я делаю, но на самом деле это просто обучающий тренажер для меня, чтобы мне было удобнее использовать дженерики.
Комментарии:
1. Это крайне сбивает с толку.
EntityManager<Entity>
по-видимому, не имеет никакого отношения кGenericManager<T>
, и он объявляет параметр типа с тем же именем, что и класс. Это странный и подверженный ошибкам способ сделать это; вы уверены, что не хотели этого делатьclass EntityManager : GenericManager<Entity>
???2. Я исправил пример. извините за путаницу .. это был долгий день
Ответ №1:
вы могли бы использовать простой пустой интерфейс менеджера для создания списка и пересечений на основе метода расширения OfType, например
public interface IGenericManager { }
public class GenericManager<T> : IGenericManager where T : Updateable { }
public class EntityManager : GenericManager<Entity> { }
var list = new List<IGenericManager>();
var entityManagers = list.OfType<EntityManager>();
Ответ №2:
Объявите IGenericManager
интерфейс, позвольте GenericManager<T> : IGenericManager
и вы можете использовать List<IGenericManager>
.
Единственным недостатком является то, что предоставляемые методы не могут быть общими.
Обновить:
interface IGenericManager
{
Type ManagerType { get; }
}
GenericManager<T> : IGenericManager
{
public Type ManagerType { get { return typeof(T) ; } }
}
Комментарии:
1. допустим, я ищу свой entitymanager в своем списке менеджеров. есть ли способ отличить, какой объект какой?
2. Обновленный ответ — теперь вы можете сделать (псевдокод):
List<IGenericManager>().Single(x => x.ManagerType == myType)
3. как насчет List<IGenericManager>() . OfType<EntityManager>() ?
Ответ №3:
Вы можете извлечь общий интерфейс для своего базового универсального менеджера и сделать его ковариантным:
public class GenericManager<T> :IGenericManager<T> where T : Updatable { }
public interface IGenericManager<out T> where T : Updatable { }
public class Updatable { }
class UpdatableX : Updatable {}
class UpdatableY : Updatable {}
После этого вы сможете поместить все свои данные в List<IGenericManager<Updatable>>
:
var list = new List<IGenericManager<Updatable>>
{new GenericManager<UpdatableX>(), new GenericManager<UpdatableY>()};
ОБНОВЛЕНИЕ: Забыл упомянуть, что это возможно только в .NET framework 4, потому что в предыдущих версиях дженерики не могли быть ковариантными или контравариантными.
Комментарии:
1. должен немного покопаться, но скоро вернусь к этому .. думаю, это больше то, что мне нужно, хотя решение Якуба было хорошим.
2. действительно ли интерфейс необходим? почему бы напрямую не применить ковариацию к аргументу шаблона GenericManager?
3. Это так. Вы не можете использовать параметры варианта в классе, только в интерфейсе или делегате.