Общий тип детского класса не позволяет родителям - PullRequest
0 голосов
/ 23 сентября 2010

Учитывая такую ​​структуру:

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

Я пытаюсь обойти тот факт, что перегрузка универсального метода не учитывает ограничений.

Что я могу сделать здесь?

@ Сандер Рейкен: Дополнительная информация.

Мне нужно использовать универсальный тип для вызова метода инфраструктуры 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 вызывает разрыв дочернего объекта obj = orm.GetObject (), поскольку T не может быть преобразован в тип 'Child'

@ Ричард Хейн:

Изначально у меня было 2 метода, каждый с ограничением на один из дочерних / родительских (в данном случае: XPObject и XPCustomObject из DevExpress ORM - 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 используется (в данном случае), чтобы иметь PK типа short (вместо int по умолчанию в XPObjects). Таким образом, единственное изменение заключается в вызове для получения объекта:

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

Разница минимальна, поэтому я хочу объединить два метода вместе.

Ответы [ 3 ]

3 голосов
/ 23 сентября 2010
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 голос
/ 23 сентября 2010

Эта часть вашего кода не имеет смысла:

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 сначала и , затем до 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, но вы можете повысить до Parent (что всегда успешно, потому что T - это Parent), а затем уменьшить до Child (который во время выполнения проверяет, действительно ли равен a Child, что, конечно, в вашем случае будет).

(Кстати, я предполагаю, что вам нужно , чтобы использовать orm.GetObject<T>, а вы не можете использовать orm.GetObject<Child>. Если вы можете, это сделает это проще , но, возможно, вы не можете, потому что criteria зависит от T.)

1 голос
/ 23 сентября 2010

Помимо того факта, что T не происходит от child, я думаю, вы захотите использовать

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

В противном случае он будет срабатывать только для вещей, которые в точности соответствуют типу Parent, а непроизводный тип.Кроме того, я не думаю, что == правильно перегружен для Type.Я думаю, что вам нужно использовать .Equals ()

Примечание. Возможно, я получил IsAssignableFrom в обратном направлении.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...