Список объектов, наследующих универсальный класс

#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. Это так. Вы не можете использовать параметры варианта в классе, только в интерфейсе или делегате.