子类的通用类型不允许父类

时间:2010-09-22 22:36:59

标签: c# generics overloading

给出这样的结构:

class Parent { }

class Child : Parent { }

我有一个方法,它采用具有约束的泛型类型,该对象的类型为Child

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

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

class implementsParent : Parent { }

class implementsChild : Child { }

使用一种implementsParent调用泛型方法将不起作用:

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

我正在努力解决重载泛型方法没有考虑约束的事实。

我可以在这做什么?

@Sander Rijken:补充信息。

我需要使用泛型类型来调用ORM框架方法,如下所示:

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导致Child obj = orm.GetObject()中断,因为T无法转换为Type'Child'

@Richard Hein:

最初,我有两个方法,每个方法都对子/父之一有一个约束(在这种情况下:来自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类型的PK(而不是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 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:1)

除了T不是来自孩子的事实,我认为你想要使用

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

否则它只会触发完全类型为Parent的东西,而不是派生类型。另外,我不认为==正确地重载了​​Type。我认为你需要使用.Equals()

注意:我可能已经向后收到了IsAssignableFrom。

答案 2 :(得分:1)

这部分代码没有意义:

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。你是对的,你不能直接 - - 但是你可以先把它Parent 再然后再到{{ 1}}。我认为这应该有效:

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,但你可以转发到Child(由于ParentT总是成功的Parent)然后向下转发到Child(运行时检查它是否真的 Child,当然在你的情况下它会是)

(顺便说一句,我假设你需要使用orm.GetObject<T>而你不能使用orm.GetObject<Child>。如果你能,这会使它变得更简单,但也许你不能,因为criteria依赖于T。)