Кастинг объекта к двум интерфейсам одновременно, для вызова общего метода

Я хочу назвать общий метод, который вынуждает входной тип 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);
    }
}

?

Отражение, вероятно, позволяет делать вызов, но я хотел бы остаться в языке.

13
задан Bruno Martinez 24 May 2010 в 23:40
поделиться

5 ответов

Ключевое слово 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? Я не знаю.

3
ответ дан 1 December 2019 в 23:47
поделиться

Я согласен с другими респондентами, что у вас, вероятно, есть проблема с дизайном, если вам нужно это сделать, но вы можете решить это с помощью прокси-объекта, который реализует оба интерфейса и делегирует вызовы двум приведенные экземпляры интерфейса неизвестного объекта. Теперь, когда вы вызываете этот метод, вы можете создать прокси для любого типа, который поддерживает оба интерфейса.

4
ответ дан 1 December 2019 в 23:47
поделиться

Похоже, вы неправильно понимаете, как работают дженерики: при вызове метода, который имеет общий параметр T , T должен быть статически известен во время компиляции. Хотя компилятор иногда может вывести его (и поэтому вам не всегда нужно явно его записывать), при вызове метода необходимо указать T . В вашем случае все, что вы знаете, это то, что obj является IA и IB , но это не дает вам достаточно информации для вызова foo , поскольку вы понятия не имеете, каким должен быть T . Вам придется либо использовать отражение, либо приведение к конкретному типу , который реализует как IA , так и IB , либо внести более серьезные изменения в дизайн.

6
ответ дан 1 December 2019 в 23:47
поделиться

вам нужно будет определить третий тип (возможно, интерфейс), который наследуется от обоих интерфейсов. если у вас есть такие ограничения, то обязательно имейте в виду. в противном случае он непригоден для использования. если это (obj - это IB, а obj - это IB) , тогда obj является именно таким типом.

0
ответ дан 1 December 2019 в 23:47
поделиться

Ваш метод 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)); 
  }
}
2
ответ дан 1 December 2019 в 23:47
поделиться
Другие вопросы по тегам:

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