【问题标题】:C# generics and type checking confusionC# 泛型和类型检查混淆
【发布时间】:2011-11-04 21:13:06
【问题描述】:

首先,一些课程:

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# 如何处理类型(或者,更尴尬的是,一般来说是泛型)的内容,所以如果这是一个简单的问题,请指出我的方向的一些阅读材料。提前致谢!

【问题讨论】:

  • 您可以使用泛型约束来解决“其中 T 必须是 Component 的子级”问题。这真的很简单 - where T : Component。这种类型的注册+通知听起来像the Observer Design Pattern,所以你可能想看看。我想你会想要做两层这种模式。

标签: c# generics types


【解决方案1】:

局部变量声明和“as”不能这样工作。 “t”是一个表达式,在运行时计算为对表示类型的对象的引用。本地 decl 和“as”期待一个程序片段,在编译时命名一个类型

您正试图将蛋糕放在蛋糕食谱书的架子上;虽然蛋糕和蛋糕食谱书密切相关,但它们并不是一回事。

如果你想在运行时判断对象c是否属于t对象所描述的类型,那么你可以在c上调用GetType并判断这两种类型是否(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 

看看你的设计,其他的东西看起来很可疑。一个通用系统实际上是一种组件列表,还是它是一个包含组件列表的东西?用推导来表达“是一种”的关系。使用包含来表达“容器”关系。汽车不是一种轮子列表;一辆车轮子列表。

【讨论】:

  • +1 表示“汽车不是车轮列表”。这可能是一个常见的陷阱,因为我最早的设计总是存在这个问题。
  • 我真的希望 C# 有一流的类型,这样你就可以做那种事情 - 有一个接受类型参数的非泛型方法调用具有该参数的泛型方法:void Foo(Type t) { Bar&lt;t&gt;(); } void Bar&lt;T&gt;() { }。这将增加 C# 的功能,但当然必须在运行时进行一些编译或反射。
【解决方案2】:

首先,你正在写作

if ((c as T) != null)

哪个更简单

if (c is T)

然后,正如 Eric 指出的那样,这些运算符需要类型,而不是包含类型元数据的变量。你需要反思,比如:

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

【讨论】:

    猜你喜欢
    • 2015-05-13
    • 2010-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-01
    • 2016-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多