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