简体   繁体   中英

C# generics and type checking confusion

To start, some classes:

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);
        }


    }

}

The error I get is "The type or namespace 't' could not be found."

I want each GenericSystem to have a Component type that it wants registered to it. This way, anything registering a new Component c simply calls GenericEngine.RegisterComponent(c) and all systems interested in that type of component register it.

Ideally, I'd like to have the code more along the lines of:

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

I suspect this isn't a terribly complicated question, and I'm missing something about how C# deals with types (or, more embarrassingly, generics in general) so if it's an easy question, please just point me in the direction of some reading material. Thanks in advance!

Local variable declarations and "as" do not work that way. "t" is an expression that at runtime evaluates to a reference to an object that represents a type . The local decl, and "as" are expecting a program fragment that at compile time names a type .

You're trying to put a cake onto a shelf of cake recipe books; though cakes and cake recipe books are intimately related, they are not the same kind of thing.

If you want to determine if at runtime, the object c is of the type described by the t object, then you can call GetType on c and determine if the two types are either (1) equal, if you demand identity, or (2) compatible, if you merely require one to be compatible with the other.


Ideally, I'd like to have the code more along the lines of:

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

OK, then say that:

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

Looking at your design, other things seem suspicious. Is a generic system actually a kind of list of components , or is it a thing that, among other things, contains a list of components? Use derivation to express "is a kind of" relationships. Use containment to express "container" relationships. A car is not a kind of list of wheels; a car has a list of wheels.

First, you're writing

if ((c as T) != null)

which is simpler

if (c is T)

Then, as Eric points out, these operators need types, not variables containing type metadata. You'll need reflection, like:

if (t.IsAssignableFrom(c.GetType()))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM