Предположим, что у меня есть следующая иерархия классов:
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 для редактирования их
Вам нужно определить интерфейс для общих методов, которые есть в B и C (назовем его Ibc), заставить B и C реализовать этот интерфейс, а затем вы можете написать:
Class D<T> where T : A, Ibc {...}
Некоторые параметры:
IdehibitedFromA
, который содержит общие методы из B
и C
. D
приведите T
в динамический
и вызовите методы динамически D
проверьте, имеете ли вы дело с B
или C
, выполните приведение и вызовите D
для B
и ] C
, они могут напрямую вызывать методы из B
и C
. (Сам не думал об этом). B
или C
, и не использует реферат A
для использования D
. Вместо этого следует использовать DB
или DC
.Но я думаю, что это так, иначе дженерики вам не понадобились. Это напрямую невозможно.
Как предлагают другие, вы можете определить интерфейс и реализовать его в 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();
}
}
Во-первых, если 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
.
Поскольку у вас нет доступа к источнику, единственный реальный ответ (если вы не хотите потерять безопасность, используя динамический
) - это явная проверка на B
/ C
и отливка.
Реализуют ли B и C один и тот же интерфейс? Это может быть лучший путь.
Ограничение where в C# не позволяет указывать несколько классов в качестве выбора. Также если вы укажете несколько where contains, то они оба должны быть удовлетворены. Для ограничения не существует логики OR. Вот спецификация: http://msdn.microsoft.com/en-us/library/bb384067.aspx
Ответы от Grzenio кажутся вам подходящими. Извлеките общее поведение в общий интерфейс для B и C. Затем вы можете использовать этот интерфейс как ограничение.