Дженерики C# - я могу заставить T быть от одного из двух вариантов?

Предположим, что у меня есть следующая иерархия классов:

Class A {...}

Class B : A  {...}

Class C : A {...}

То, что я в настоящее время имею,

Class D<T> where T : A {...}

но я хотел бы что-то вроде формы

Class D<T> where T in {B,C}

Это происходит из-за некоторого нечетного поведения, я не ответственен за то, где B и C имеют общепринятые методики, которые не находятся в A, но было бы хорошо смочь назвать их в D на T.

Примечание: У меня нет доступа к A, B или C для редактирования их

22
задан Jean-Bernard Pellerin 31 March 2011 в 22:05
поделиться

7 ответов

Вам нужно определить интерфейс для общих методов, которые есть в B и C (назовем его Ibc), заставить B и C реализовать этот интерфейс, а затем вы можете написать:

Class D<T> where T : A, Ibc {...}
24
ответ дан 29 November 2019 в 04:36
поделиться

Некоторые параметры:

  1. Создайте интерфейс IdehibitedFromA , который содержит общие методы из B и C .
    Похоже, это невозможно из вашего вопроса
  2. В D приведите T в динамический и вызовите методы динамически
    Самое простое решение , если вы можете использовать .Net 4
  3. В D проверьте, имеете ли вы дело с B или C , выполните приведение и вызовите
    Will быть проверено компилятором и возможно из .Net 2
  4. Ответ Дэна Тао : Создайте конкретную реализацию D для B и ] C , они могут напрямую вызывать методы из B и C . (Сам не думал об этом).
    Будет работать, только если "пользователь-источник" знает, что имеет дело с B или C , и не использует реферат A для использования D . Вместо этого следует использовать DB или DC .Но я думаю, что это так, иначе дженерики вам не понадобились.
2
ответ дан 29 November 2019 в 04:36
поделиться

Это напрямую невозможно.

Как предлагают другие, вы можете определить интерфейс и реализовать его в B и C.

Если это невозможно (например, если эти классы находятся вне вашего контроля), я могу предложить следующее: сначала начните с абстрактного класса, который включает все функциональные возможности, которых вы можете достичь с помощью любого T, производного от A. Затем, допустим, у вас есть некоторые методы, существующие для B и C, которые не являются частью A. В D вы можете сделать эти абстрактные методы реализуемыми подклассами:

public abstract class D<T> where T : A
{
    protected T _member;

    public void DoSomethingAllTsCanDo()
    {
        _member.DoSomething();
    }

    public abstract void DoSomethingOnlyBAndCCanDo();
}

Затем вы можете наследоваться от базового класса для каждого типа B и C и переопределить абстрактный метод(ы) для обеспечения соответствующей функциональности:

public class DB : D<B>
{
    public override void DoSomethingOnlyBAndCCanDo()
    {
        _member.DoSomethingOnlyBCanDo();
    }
}

public class DC : D<C>
{
    public override void DoSomethingOnlyBAndCCanDo()
    {
        _member.DoSomethingOnlyCCanDo();
    }
}
9
ответ дан 29 November 2019 в 04:36
поделиться

Во-первых, если B и C имеют общие методы, это недостаток дизайна, что они не имеют общего интерфейса. Тем не менее, вы можете исправить это, даже не имея доступа к B и C.
Возможно создание общего интерфейса. Предположим, у вас есть:

public class A
{
}
public class B : A
{
    public void Start() { }
}
public class C : A
{
    public void Start() { }
}

Вы можете создать общий интерфейс:

public interface IStartable
{
    void Start();
}

И использовать его в классах, производных от B и C:

public class BetterB : B, IStartable
{
}
public class BetterC : C, IStartable
{
}

Возможно, вы не сможете добиться этого, если получите экземпляры B и C как есть, но это можно рассмотреть, если вы их создадите. Фактически, со специализированными классами B и C вы можете использовать интерфейс вместо D .

5
ответ дан 29 November 2019 в 04:36
поделиться

Поскольку у вас нет доступа к источнику, единственный реальный ответ (если вы не хотите потерять безопасность, используя динамический ) - это явная проверка на B / C и отливка.

0
ответ дан 29 November 2019 в 04:36
поделиться

Реализуют ли B и C один и тот же интерфейс? Это может быть лучший путь.

3
ответ дан 29 November 2019 в 04:36
поделиться

Ограничение where в C# не позволяет указывать несколько классов в качестве выбора. Также если вы укажете несколько where contains, то они оба должны быть удовлетворены. Для ограничения не существует логики OR. Вот спецификация: http://msdn.microsoft.com/en-us/library/bb384067.aspx

Ответы от Grzenio кажутся вам подходящими. Извлеките общее поведение в общий интерфейс для B и C. Затем вы можете использовать этот интерфейс как ограничение.

0
ответ дан 29 November 2019 в 04:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: