Я хочу назвать общий метод, который вынуждает входной тип T реализовывать два интерфейса:
interface IA { }
interface IB { }
void foo<T>(T t) where T : IA, IB { }
Как я могу зафиксировать последнюю строку
void bar(object obj)
{
if (obj is IA && obj is IB)
{
foo((IA && IB)obj);
}
}
?
Отражение, вероятно, позволяет делать вызов, но я хотел бы остаться в языке.
Ключевое слово dynamic в C # 4.0 освобождает вас (в основном) от тюрьмы? В конце концов - вы уже проводите проверку типов.
interface IC : IA, IB { }
void bar(object obj)
{
if (obj is IA && obj is IB)
{
IC x = (dynamic)obj;
foo(x);
}
}
Это прерывается, если foo пытается преобразовать параметр в T? Я не знаю.
Я согласен с другими респондентами, что у вас, вероятно, есть проблема с дизайном, если вам нужно это сделать, но вы можете решить это с помощью прокси-объекта, который реализует оба интерфейса и делегирует вызовы двум приведенные экземпляры интерфейса неизвестного объекта. Теперь, когда вы вызываете этот метод, вы можете создать прокси для любого типа, который поддерживает оба интерфейса.
Похоже, вы неправильно понимаете, как работают дженерики: при вызове метода, который имеет общий параметр T
, T
должен быть статически известен во время компиляции. Хотя компилятор иногда может вывести его (и поэтому вам не всегда нужно явно его записывать), при вызове метода необходимо указать T
. В вашем случае все, что вы знаете, это то, что obj
является IA
и IB
, но это не дает вам достаточно информации для вызова foo
, поскольку вы понятия не имеете, каким должен быть T
. Вам придется либо использовать отражение, либо приведение к конкретному типу , который реализует как IA
, так и IB
, либо внести более серьезные изменения в дизайн.
вам нужно будет определить третий тип (возможно, интерфейс), который наследуется от обоих интерфейсов. если у вас есть такие ограничения, то обязательно имейте в виду. в противном случае он непригоден для использования. если это (obj - это IB, а obj - это IB)
, тогда obj является именно таким типом.
Ваш метод bar
также должен быть универсальным, с теми же ограничениями, что и foo
.
Но если вы действительно хотите решить эту проблему, вы можете создать оболочку для объекта, реализующего оба интерфейса, которые делегируют все вызовы обернутым экземплярам:
class ABWrapper : IA, IB {
IA _a;
IB _b;
public Wrapper(IA a) {
if (!(a is IB)) throw new ArgumentException();
_a = a;
_b = (IB)a;
}
public Wrapper(IB b) {
if (!(b is IA)) throw new ArgumentException();
_a = (IA)b;
_b = b;
}
// explicit implementation for IA and IB delegating to _a and _b
}
И использовать ее следующим образом:
static void bar(object obj) {
if (obj is IA && obj is IB) {
foo(new ABWrapper((IA)obj));
}
}