Для начала несколько занятий:

public abstract class Component
{
    GenericSystem mySystem;

    public Component() { mySystem = null;}

    public void SetSystem(GenericSystem aSystem) { mySystem = aSystem; }
}

public class PhysicsComponent : Component
{
    int pos;    

    public PhysicsComponent(int x) : base() { pos = x; }
}


public abstract class GenericSystem : List<Component>
{
    public Type ComponentType;
    public GenericSystem(Type componentType)
    { ComponentType = componentType; }
    public void RegisterComponent(c)
    {
        Add(c);
        c.SetSystem(this);
    }
}

public class PhysicsSystem : GenericSystem
{
    public PhysicsSystem() : base(typeof(PhysicsComponent)) { }
}

public static GenericEngine
{
    List<GenericSystem> systems = new List<GenericSystem>();

    //... Code here that adds some GenericSystems to the systems ...

    public static void RegisterComponent(Component c)
    {
        foreach(GenericSystem aSystem in systems)
        {
            Type t = aSystem.ComponentType;
            //PROBLEM IS HERE
            t c_as_t = c as t;
            //
            if ( c_as_t != null)
                aSystem.RegisterComponent(c);
        }


    }

}

Я получаю сообщение об ошибке: «Не удалось найти тип или пространство имен 't'».

Я хочу, чтобы у каждого GenericSystem был тип Component, который он хочет зарегистрировать для него. Таким образом, все, что регистрирует новый Component c, просто вызывает GenericEngine.RegisterComponent(c), и все системы, заинтересованные в этом типе компонента, регистрируют его.

В идеале я бы хотел, чтобы код был больше похож на:

     //where T must be a child of Component
    public abstract class GenericSystem<T> : List<Component> { /... }
    public class PhysicsSystem : GenericSystem<PhysicsComponent>

Я подозреваю, что это не очень сложный вопрос, и мне что-то не хватает о том, как C # работает с типами (или, что еще более неприятно, с универсальными шаблонами в целом), поэтому, если это простой вопрос, пожалуйста, просто укажите мне в направлении некоторого чтения материал. Заранее спасибо!

1
user312364 27 Авг 2011 в 02:25

2 ответа

Лучший ответ

Объявления локальных переменных и "as" не работают. «t» - это выражение, которое во время выполнения оценивает ссылку на объект, представляющий тип . Локальный decl и as ожидают фрагмента программы, который во время компиляции называет тип .

Вы пытаетесь положить торт на полку книг с рецептами тортов; Хотя торты и книги рецептов пирожных тесно связаны, это не одно и то же.

Если вы хотите определить, имеет ли во время выполнения объект c тип, описанный объектом t, вы можете вызвать GetType для c и определить, являются ли эти два типа (1) равными, если вы требуете идентичность, или (2 ) совместимы, если вам просто требуется, чтобы один был совместим с другим.


В идеале я бы хотел, чтобы код был больше похож на:

 //where T must be a child of Component
public abstract class GenericSystem<T> : List<Component>

Хорошо, тогда скажи, что:

public abstract class GenericSystem<T> : List<Component> where T : Component 

Глядя на ваш дизайн, все остальное кажется подозрительным. Является ли универсальная система на самом деле своего рода списком компонентов или это, помимо прочего, содержит список компонентов? Используйте вывод, чтобы выразить «это своего рода» отношения. Используйте сдерживание, чтобы выразить «контейнерные» отношения. Автомобиль - это не список колес; автомобиль имеет список колес.

9
Eric Lippert 26 Авг 2011 в 22:35

Сначала ты пишешь

if ((c as T) != null)

Что проще

if (c is T)

Затем, как указывает Эрик, этим операторам нужны типы, а не переменные, содержащие метаданные типа. Вам понадобится отражение, например:

if (t.IsAssignableFrom(c.GetType()))
1
Ben Voigt 26 Авг 2011 в 22:32