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

发布于 2024-09-24 17:17:14 字数 1900 浏览 0 评论 0原文

给定这样的结构:

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 无法转换为类型“Child”

@Richard Hein:

最初,我有 2 个方法,每个方法都对子/父之一有约束(在本例中:来自 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(而不是 XPObject 上的默认 int)。所以唯一的变化是获取对象的调用:

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

差异很小,所以我想将这两个方法合并在一起。

Given a structure like this:

class Parent { }

class Child : Parent { }

I have a method that takes a generic type with a constraint that the object is of type Child

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

the only problem is that, if I have:

class implementsParent : Parent { }

class implementsChild : Child { }

calling the generic method with a type of implementsParent won't work:

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

I'm trying to work around the fact that overloading a generic method doesn't take into account constraints.

What can I do here?

@Sander Rijken: Additional information.

I need to use the generic type to call an ORM framework method like so:

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

having the constraint be where T : Parent causes the Child obj = orm.GetObject() to break because T cannot be converted to Type 'Child'

@Richard Hein:

Originally, I had 2 methods, each with a constraint to one of child/parent (in this case: XPObject and XPCustomObject from the DevExpress ORM - XPObject inherits from XPCustomObject).

The methods look like so:

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

XPCustomObject is used (in this case) to have PKs of type short (instead of the default int on XPObjects). So the only change is in the call to get the object:

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

The difference is minimal, so I want to merge the two methods together.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

二手情话 2024-10-01 17:17: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);
    }
}
doSomething<implementsParent>();

This fails because it doesn't meet the type constraint. T isn't derived from Child

Did you mean to declare it:

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

Edit: This will work, given the requirement you added.

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);
    }
}
花之痕靓丽 2024-10-01 17:17:14

除了 T 不是从子派生这一事实之外,我认为您会想要使用

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

否则,它只会针对完全是 Parent 类型而不是派生类型的事物触发。另外,我认为 == 对于 Type 来说没有正确重载。我认为你需要使用 .Equals()

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

Aside from the fact that T doesn't derive from child, I think you'd want to use

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

Otherwise it'll only fire for things that are exactly the type Parent, not a derived type. Also, I don't think == is properly overloaded for Type. I think you need to use .Equals()

Note: I may have gotten the IsAssignableFrom backwards.

梦途 2024-10-01 17:17: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
    {

如果您希望能够传递 Parent,则绝对需要将约束定义为 T : Parent

您说您的问题是无法将 orm.GetObject 的输出强制转换为 Child。你是对的,你不能直接将其转换 - 但你可以将其转换为Parentfirstthen。我认为这应该可行:

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   |
            └─────────┘  └───────┘

我认为这向您展示了为什么不能直接从TChild,但您可以向上转换为 Parent (这总是成功的,因为 TParent),然后向下转换为 Child (这会在运行时检查它是否真的一个Child,这当然在你的情况就会如此)。

(顺便说一句,我假设您需要使用orm.GetObject并且您不能使用orm .GetObject 如果可以,那就更简单了,但也许不能,因为 criteria 取决于 T。)

This part of your code doesn’t make sense:

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
    {

You definitely need to define the constraint as T : Parent if you want to be able to pass in a Parent.

You said that your problem is that you can’t cast the output of orm.GetObject<T> to Child. You are right, you can’t cast it directly — but you can cast it to Parent first and then to Child. I think this should work:

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

From the point of view of the compiler, T is like a member of the class hierarchy, a bit like this:

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

I think this shows you why you can’t cast directly from T to Child, but you can upcast to Parent (which always succeeds because T is a Parent) and then downcast to Child (which does the runtime check for whether it really is a Child, which of course in your case it will be).

(By the way, I am assuming that you need to use orm.GetObject<T> and you can’t use orm.GetObject<Child>. If you can, that would make it simpler, but maybe you can’t because the criteria depend on T.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文