Интерфейсы больше не работают при использовании пользовательского класса коллекции - PullRequest
1 голос
/ 16 февраля 2011

Я создал класс MonitoredCollection<T>, который в основном инкапсулирует / имитирует список, но позволяет мне запускать события при определенных вызовах.

Однако теперь, где бы ни был параметр, который принимает MonitoredCollection, где T - это интерфейс, я больше не могу передавать MonitoredCollection<T>, где T - это класс, реализующий этот интерфейс, как я мог бы с List.

Я всегда думал, что интерфейсы - это «особенность» языка, и поэтому мне не нужно ничего реализовывать, чтобы поддерживать это, так что я пропустил?

РЕДАКТИРОВАТЬ: Извините, я допустил ошибку в этом вопросе, так как Жоао правильно указал, что List никогда не работал в этом случае, поэтому вопрос такой, какой он есть без него!

Ответы [ 2 ]

3 голосов
/ 16 февраля 2011

Предположим, у вас есть экземпляр MonitoredCollection<SomeObject>, и вы хотите рассматривать его как экземпляр MonitoredCollection<ISomeInterface>, где SomeObject фактически реализует ISomeInterface.Это не создает никаких проблем для извлечения элементов из коллекции, поскольку объект типа SomeObject может быть преобразован в тип интерфейса ISomeInterface.

Однако для всех методов в вашей коллекции, которые изменяют коллекциюНапример, такие, которые присваивают новое значение индексу или вставляют новый элемент в коллекцию, это приведение создало целый набор проблем.Я бы предположил, что у вашего MonitoredCollection<SomeObject> экземпляра будет такой метод, как Add(SomeObject obj), который вставит новый объект в коллекцию.После приведения подпись для этого метода будет Add(ISomeInterface obj).Кажется, это имеет смысл, но не все ISomeInterface объекты являются НЕОБХОДИМЫМИ SomeObject экземплярами.

Поскольку приведенный объект будет разрешать операции с коллекцией, которые не разрешены исходным объектом, среда выполнения неразрешить этот актерский составВ C # 4.0 введены ковариация и контравариантность, чтобы явно указать, что является допустимым для приведений этого типа, вы можете изучить их для решения этой проблемы.Однако вам действительно повезет только с версией вашей коллекции, доступной только для чтения (подумайте List<T>.AsReadOnly()).

1 голос
/ 16 февраля 2011

К сожалению, вы не можете сделать это с помощью списка.Компилятор все еще не может преобразовать типы.Вам нужно использовать универсальный метод.Смотрите код ниже:

class Test
{
    void DoTest()
    {
        MonitoredList<IInterface> mlist1 = new MonitoredList<Inherited>(); //Error
        MonitoredList<Inherited> mlist2 = new MonitoredList<Inherited>();
        DoSomething1(mlist2); //Error converting MonitoredList<Inherited> to MonitoredList<IInterface>

        MonitoredList<IInterface> list1 = new MonitoredList<Inherited>(); //Error
        MonitoredList<Inherited> list2 = new MonitoredList<Inherited>();
        DoSomething2(list2); //Error converting List<Inherited> to List<IInterface>

        DoSomething3<Inherited>(mlist2); //Works fine
        DoSomething3(mlist2); //<Inherited> is redundant
    }

    void DoSomething1(List<IInterface> list)
    { }

    void DoSomething2(MonitoredList<IInterface> list)
    { }

    //Generic method
    void DoSomething3<T>(MonitoredList<T> list) where T : IInterface
    { }
}

interface IInterface { }

class Inherited : IInterface { }

class MonitoredList<T> { }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...