Нестрогие ограничения параметров нескольких типов интерфейса?

StackOverflow https://stackoverflow.com/questions/1891656

  •  19-09-2019
  •  | 
  •  

Вопрос

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

У меня есть два интерфейса - давайте назовем их Ионная линия и IOffline ( Оффлайн ).

Они тесно связаны тем, что описывают почти идентичные контракты, но одно из ключевых различий между ними заключается в контексте, в котором будут использоваться конкретные реализации.Это не совсем мои обстоятельства, но это хорошо иллюстрирует проблему.

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

Достаточно просто:

public void DoStuff<T>(string foo) where T : IOnline {}

Проблема заключается в реализации кода для методов, которые могут работать с любым типом.Я думал, что это было бы правильно, но при чтении ошибки компиляции мое ожидание, что ограничение будет интерпретировано как "разрешить использование любого типа T в общем случае здесь, если они реализуют IOnline ИЛИ IOffline", на самом деле интерпретируется как "Разрешить использование любого типа T в общем случае здесь, если они реализуют ОБА".

public void DoStuff<T>(string foo) where T : IOnline, IOffline {}

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

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

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

Это было полезно?

Решение

Предоставление нескольких ограничений, как в вашем втором примере, действительно является аддитивным.В Страница MSDN, посвященная общим ограничениям есть немного об этом.

Можете ли вы сделать так, чтобы ваши два интерфейса наследовались от базового интерфейса, и ограничить методы базовым типом?

Другие советы

Возможно, это не ответ на ваш вопрос, но у меня спонтанно возникает ощущение, что вы, возможно, захотите провести рефакторинг своих интерфейсов.Из вашего вопроса:

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

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

Я думаю, что стандартный способ в .NET сделать это - иметь один интерфейс, который содержит как ваши функции IOnline, так и IOffline, а затем некоторые свойства, указывающие, какие функции фактически реализованы в определенном классе.Вы видите этот шаблон в разных местах .NET с такими вещами, как метод Seek(), который может быть реализован, а может и не быть, и свойство CanSeek, которое вы можете протестировать.

Возможно, это не самый чистый OO-дизайн, но он работает.

Теряет часть проверки во время компиляции, но я не вижу никакого способа обойти это...Вам действительно нужно выбрать, что бы вы предпочли использовать (я предполагаю, что вы предпочтете онлайн).:

public void DoStuff<T>(string foo)
{
    Type type = typeof(T);
    if(type.GetInterfaces().Contains(typeof(IOnline)))
         doStuffOnline<T>(foo);
    else if(type.GetInterfaces().Contains(typeof(IOffline)))
         doStuffOffline<T>(foo);
    else
         throw new Exception("T must implement either IOnline or IOffline");
}

private void doStuffOnline<T>(string foo){ // can assume T : IOnline }
private void doStuffOffline<T>(string foo){ // can assume T : IOffline }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top