代码之家  ›  专栏  ›  技术社区  ›  Steven Evers

子类的泛型类型不允许父类

  •  0
  • Steven Evers  · 技术社区  · 14 年前

    给定这样的结构:

    class Parent { }
    
    class Child : Parent { }
    

    static void doSomething<T>() where T : Child
    {
        if (typeof(T) == typeof(Parent))
        {
            /* ... */
        }
        else if (typeof(T) == typeof(Child))
        {
            /* ... */
        }
    }
    

    唯一的问题是,如果我有:

    class implementsParent : Parent { }
    
    class implementsChild : Child { }
    

    使用ImplementsAgent类型调用泛型方法将不起作用:

    doSomething<implementsParent>(); // compile error
    doSomething<implementsChild>(); // works fine
    

    我能在这里做什么?

    @桑德里杰肯:补充资料。

    static void doSomething<T>() where T : Child
    {
        if (typeof(T) == typeof(Parent))
        {
            Parent obj = orm.GetObject<T>(criteria);
        }
        else if (typeof(T) == typeof(Child))
        {
            Child obj = orm.GetObject<T>(criteria);
        }
    }
    

    使约束位于T:Parent导致子对象=orm.GetObject对象()中断,因为T无法转换为类型“Child”

    @理查德·海因:

    最初,我有两个方法,每个方法都对child/parent(在本例中:DevExpress ORM中的XPObject和XPCustomObject-XPObject继承XPCustomObject)中的一个进行了约束。

    方法如下:

    static void removeBlank<T>(UnitOfWork uow) where T : XPObject
    {
        T blank = uow.GetObjectByKey<T>(0):
        if (blank != null)
        {
            blank.Delete();
            uow.CommitChanges();
        }
    }
    

    XPCustomObject用于(在本例中)具有short类型的PKs(而不是XPObjects上的默认int)。所以唯一的变化是调用获取对象:

    static void removeBlankCustomObject<T>(UnitOfWork uow) where T : XPCustomObject
    {
        T blank = uow.GetObjectByKey<T>((short)0);    
        if (blank != null)
        {
            blank.Delete();
            uow.CommitChanges();
        }
    }
    

    差别很小,所以我想把这两种方法合并在一起。

    3 回复  |  直到 14 年前
        1
  •  3
  •   Sander Rijken    14 年前
    doSomething<implementsParent>();
    

    此操作失败,因为它不满足类型约束。 T 不是从 Child

    你的意思是说:

    static void doSomething<T>() where T : Parent
    

    编辑:根据您添加的要求,这将起作用。

    static void doSomething<T>() where T : Parent
    {
        if (typeof(T) == typeof(Parent))
        {
            T obj = orm.GetObject<T>(criteria);
        }
        else if (typeof(T) == typeof(Child))
        {
            T obj = orm.GetObject<T>(criteria);
        }
    }
    
        2
  •  1
  •   Hounshell    14 年前

    撇开事实不说T不是从child派生出来的,我想你应该用

    if (typeof(T).IsAssignableFrom(typeof(Parent))
      ...
    

    否则,它只会为完全是父类型而不是派生类型的对象触发。另外,我不认为==对于类型是正确重载的。我认为您需要使用.Equals()

    注意:我可能从后面得到了isassignable。

        3
  •  1
  •   Timwi    14 年前

    这部分代码没有意义:

    static void doSomething<T>() where T : Child
                            //   ^^^^^^^^^^^^^^^    This says that T must be a Child,
                            //                      which necessarily means it is not
                            //                      going to be a Parent
    {
        if (typeof(T) == typeof(Parent))   //  <--  Therefore, this will never hit
        {
    

    您肯定需要将约束定义为 T : Parent 如果你想通过考试 Parent

    你说你的问题是你不能投出 orm.GetObject<T> Child . 你说得对,你不能投 直接地 但你可以把它投给 第一 孩子 . 我认为这应该管用:

    static void doSomething<T>() where T : Parent
    {
        if (typeof(T) == typeof(Parent))
        {
            Parent obj = (Parent) orm.GetObject<T>(criteria);
        }
        else if (typeof(T) == typeof(Child))
        {
            Child obj = (Child) (Parent) orm.GetObject<T>(criteria);
        }
    }
    

    从编译器的角度来看, T 类似于类层次结构的成员,有点像这样:

                      ┌──────────┐
                      |  Parent  |
                      └─┬──────┬─┘
                        │      │
                        ↓      ↓
                ┌─────────┐  ┌───────┐
                |  Child  |  |   T   |
                └─────────┘  └───────┘
    

    我想这说明了为什么你不能直接从 起源 (总是成功,因为 T型 是一个 孩子 (运行时会检查 ,当然在你的情况下是这样的)。

    (顺便说一句,我想你 使用 orm.GetObject和lt;T> 铁路超高 使用 orm.GetObject<Child> . 如果你可以的话,那就简单了,但也许你不能,因为 criteria 依靠 T型 .)