Наследование метода из интерфейса класса с помощью аргумента подтипа: возможно ли это?

#c# #.net

#c# #.net

Вопрос:

Допустим, я наследую от IMyManager setModel. Если бы я это реализовал, я бы обычно написал:

 using lib.model;

namespace MyComponents
{
    public class MyManager:IMyManager
    {

        public void SetModel(ILibModel model)
        {

        }

    }
}
  

Это нормально для компилятора.

Теперь предположим, что вместо ILibModel я передаю конкретный класс MyModel, который реализует ILibModel.

Почему компилятор не принимает это, тогда как MyModel имеет тип ILibModel :

 namespace MyComponents
{
    public class MyManager:IMyManager
    {

        public void SetModel(MyModel model) {

        }
    }
}
  

Ответ №1:

Предполагая, что это MyModel реализует ILibModel причину, по которой это не работает, заключается в том, что, хотя все MyModel типы являются ILibModel типами, обратное не выполняется. Это означает, что не все ILibModel типы являются MyModel типами.

В интерфейсе явно указано, что он ДОЛЖЕН принимать ILibModel типы. Итак, реализация, которая принимает just MyModel , не соответствует вашему контракту на интерфейс из-за того факта, что тип, скажем, MyOtherModel который также реализует ILibModel , является допустимым типом, который должен передаваться на основе контракта вашего интерфейса.

Единственным способом обойти это было бы потенциально использовать обобщения в интерфейсе. Примером является:

 public interface IMyManager<TModel>
    where T : ILibModel
{
    void SetModel(TModel model);
}

public class MyManager : IMyManager<MyModel>
{
    void SetModel(MyModel model)
    {

    }
}
  

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

Комментарии:

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

2. Спасибо за дженерики, посмотрим, подойдет ли это.

Ответ №2:

Потому что вы предоставляете перегрузку для функции setModel. Что касается компилятора, возможно, вы хотите разрешить программисту делать что-то более конкретное с конкретным типом, одновременно выполняя что-то еще с версией интерфейса.

Ответ №3:

потому что кто-то мог позже написать:

 ((IMyManager)myManager).SetModel(new OtherClassThatImplementsILibModel());
  

Ответ №4:

Потому что так IMyManager определяется SetModel .