Почему я не могу реализовать интерфейс таким образом?
Возможный дубликат:
Поддерживает ли С# поддержку ковариации типа типа?
Я не уверен, что я просто глуп...
Если у меня есть интерфейс:
public interface IMoop
{
object Moop();
}
Почему я не могу реализовать его так (я предполагаю, что это будет использовать неявное ковариательство?)
public class MoopImplementor : IMoop
{
string Moop();
}
Любой экземпляр MoopImplementor выполнит контракт, указанный IMoop, поэтому кажется, что это должно быть хорошо.
Пожалуйста, просветите меня:)
РЕДАКТИРОВАТЬ: быть понятным - поскольку класс реализации возвращает то, что наследуется от возвращаемого типа метода Interfaced - я считаю, что это должно работать. В частности, a string
IS a object
. (и то же самое относится к любой другой цепочке целостности).
Ответы
Ответ 1
С# не поддерживает ковариацию возвращаемого типа для целей реализации интерфейса или переопределения виртуального метода. См. Этот вопрос для деталей:
Поддерживает ли С# поддержку ковариации типа типа?
С# поддерживает общую ковариацию и контравариантность интерфейсов и типов делегатов, которые строятся с ссылочными типами для аргументов типа с С# 4.
И С# поддерживает ковариацию возвращаемого типа при преобразовании метода, возвращающего ссылочный тип, в тип делегата, тип возврата которого является совместимым ссылочным типом. (И аналогичным образом он поддерживает контравариантность параметров параметров.)
Если эта тема вас интересует, я написал много статей, в которых обсуждаются различные варианты различий, которые С# делает и не поддерживает. См.
https://blogs.msdn.microsoft.com/ericlippert/tag/covariance-and-contravariance/
для деталей.
Ответ 2
Поскольку интерфейс указывает, что метод ДОЛЖЕН вернуть object
. A string
может наследовать от object
, но интерфейс указывает метод, который возвращает гораздо более общий тип.
Имейте в виду, что ничего не мешает вам сделать следующее:
public object Moop()
{
return "Some new string";
}
Ответ 3
Разумная работа:
public class MoopImplementor : IMoop {
public string Moop() { ... }
object IMoop.Moop() { return Moop(); }
}
Это позволяет публичной реализации на MoopImplementor
иметь более точный тип, сохраняя при этом требования к интерфейсу.
Ответ 4
Вы не выполняете контракт. Однако вы можете сделать это с помощью дженериков:
public interface IMoop<T>
{
T Moop();
}
public class MoopImplementor : IMoop<string>
{
public string Moop() { return ""; }
}
Ответ 5
Из Спецификация языка С#:
13.4.4 Отображение интерфейса
Для целей сопоставления интерфейсов член класса A соответствует элемент интерфейса B, когда:
- A и B - это методы, а имя type и формальные списки параметров A и B идентичны.
Обратите внимание, что он ничего не говорит о наследовании или конвертируемости! Тип возврата должен быть идентичным.