Существует ли способ объявить переменную, которая реализует несколько интерфейсов в .NET?

Подобный этому вопросу о Java. Я хотел бы указать, что переменная реализует несколько интерфейсов. Например,

private {IFirstInterface, ISecondInterface} _foo;

public void SetFoo({IFirstInterface, ISecondInterface} value)
{
    _foo = value;
}

Требования:

  • У меня нет способности добавить интерфейс для больше всего ввода, который был бы передан в Foo. Таким образом, я не могу создать третий интерфейс, который наследовался IFirstInterface и ISecondInterface.
  • Я хотел бы постараться не делать содержание класса универсальным, если возможный, потому что тип Foo не имеет непосредственное отношение к классу и пользователю, вероятно, не будет знать это во время компиляции.
  • Я должен использовать нечто для методов доступа в обоих интерфейсах в более позднее время.
  • Я хотел бы сделать это в компиляторе безопасный путь, т.е. никакая попытка бросить к интерфейсу прежде, чем попытаться использовать его. Если нечто не реализует оба интерфейса, то довольно мало функциональности не будет работать правильно.

Действительно ли это возможно?

Править: Я хотел это несколько раз по различным причинам. В этом экземпляре это - потому что я изменяю ряд свойств от ObservableCollections до ReadOnlyObservableCollections. У меня есть класс помощника, который создает проекцию из источника ObservableCollection к другому Набору. Так как ReadOnlyObservableCollection не наследовался ObservableCollection, и мне только нужны операции в IList и INotifyCollectionChanged, я надеялся сохранить свой исходный набор как комбинацию этих двух интерфейсов вместо того, чтобы требовать ObservableCollection.

18
задан Community 23 May 2017 в 12:01
поделиться

3 ответа

Если вы хотите ограничить свой метод SetFoo , чтобы он принимал только параметры, реализующие эти два интерфейса, тогда вы в удачи:

public void SetFoo<T>(T value) where T : IFirstInterface, ISecondInterface
{
    _foo = value;
}

С этого момента, когда вы захотите получить доступ к своему члену _foo в качестве одного из этих двух интерфейсов, вам просто нужно будет получить к нему доступ через приведение типов: (IFirstInterface) _foo или (ISecondInterface) _foo соответственно.

Вы действительно сказали, что не хотите прибегать к приведению типов для безопасности во время компиляции; но я думаю, что если вы найдете способ гарантировать, что _foo будет инициализирован с использованием SetFoo выше, вы можете спокойно использовать все, что захотите.


Я только что понял, что ниже описывается то, что вы конкретно указали в вопросе, который не хотел делать. Итак, я говорю, следуйте вышесказанному.

Другая идея: поскольку похоже, что этот объект _foo является членом класса (я основываю это предположение на _ в имени переменной), вы можете определить ваш класс таким образом:

class YourClassThatHasAFoo<T> where T : IFirstInterface, ISecondInterface {
    private T _foo;

    public void SetFoo(T value) {
        _foo = value;
    }
}

Имеет ли это смысл, очевидно, зависит от вашего конкретного сценария. Вам обязательно нужно обдумать это, поскольку классы с такими ограничениями иногда приводят к проблемам, которых вы, возможно, не ожидали в будущем (например, SetFoo теперь должен принимать параметр типа T , а не просто какой-либо класс, реализующий ваши два интерфейса).

17
ответ дан 30 November 2019 в 08:21
поделиться

Переменная в .NET имеет тип, а типы могут реализовывать несколько интерфейсов. Примерно так:

public interface Interface1 { }
public interface Interface2 { }
public class SupportsMuliple : Interface1, Interface2 { }

Но из вашего вопроса кажется, что вы хотите, чтобы переменная реализовывала несколько интерфейсов, не имея типа, который реализует эти интерфейсы. На самом деле это невозможно, но вы могли бы «на лету» сгенерировать тип, который реализует интерфейсы и скрыть тот факт, что существует настоящий тип, который творит чудеса. Библиотека имитации moq делает это с помощью Castle DynamicProxy .

2
ответ дан 30 November 2019 в 08:21
поделиться

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

Один вариант МОЖЕТ быть возможен с использованием универсальных шаблонов, хотя на самом деле это будет работать только для функции, а не для свойства.

public void Foo<T>(T arg)
    where T : IFirstInterface
    where T : ISecondInterface
{
    ...
}

Используя вывод типа, вы должны иметь возможность вызывать его следующим образом:

ConcreteType bar = new ConcreteType(); // this implements both

Foo(bar);
6
ответ дан 30 November 2019 в 08:21
поделиться
Другие вопросы по тегам:

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