#c# #generics
#c# #общие
Вопрос:
Рассмотрим эти два абстрактных класса. MyClass2 расширяет мой базовый класс и переопределяет виртуальный метод. Обратите внимание, что он также определяет TValue MyBaseClass как IList…
public abstract class MyBaseClass<TKey, TValue>
{
public virtual IList<TValue> DoSomeStuff()
{
IList<TValue> resu<
....
return restu<
}
}
public abstract class MyClass2<TKey, TValue>: MyBaseClass<TKey, IList<TValue>>
{
public override IList<TValue> DoSomeStuff()
{
IList<TValue> resu<
....
return restu<
}
}
Этот код не компилируется. Жалоба касается возвращаемого типа MyClass2.doSomeStuff. Ошибка «Не удается изменить тип возвращаемого значения при переопределении метода» IList<TValue> MyClass2<TKey, TValue>.DoSomeStuff()
«
Я не совсем понимаю, почему это неправильно. Почему бы компилятору или .net не считать, что значение переопределенного метода равно значению MyClass2?
Ответ №1:
Проблема в вашей части базового класса:
public abstract class MyClass2<TKey, TValue>: MyBaseClass<TKey, IList<TValue>>
Замените IList<TValue>
на TValue
, и это сработает — метод уже возвращает IList
.
Ответ №2:
TValue
Параметр вашего базового класса, унаследованный вашим подклассом, фактически IList<TValue>
соответствует объявленному вашим подклассом. Внутренний TValue
относится к вашему подклассу.
Итак, если вы пытаетесь переопределить существующий виртуальный метод, который принадлежит базовому классу, на самом деле ожидается, что возвращаемый тип будет IList<IList<TValue>>
; то есть IList
из TValue
, который принадлежит вашему базовому классу, а не подклассу.
Комментарии:
1. хммм .. тогда, я думаю, единственный способ сохранить тип неизменным — это «обобщить» сам метод. обобщения и наследование, похоже, вызывают некоторые проблемы.
2. @mike01010 Из ограниченного кода, который вы показали, я бы изменил класс на
MyClass2<TKey, TValue>: MyBaseClass<TKey, TValue>
вместо этого, если вы хотитеDoSomeStuff
все еще возвращатьIList<TValue>
Ответ №3:
Вы получаете ошибку, потому что TValue
дочерний класс на самом деле IList<TValue>
находится в базовом классе, поэтому сигнатура метода (как ее видит ваш базовый класс) будет IList<IList<TValue>>
которая, очевидно, не соответствует сигнатуре виртуального метода.
Чтобы получить соответствующие типы, вам придется изменить подпись:
public override TValue DoSomeStuff()
{
TValue resu<
return resu<
}
Комментарии:
1. Вместо этого я бы изменил сигнатуру виртуального метода.
2. @BoltClock — Все зависит от того, какой из них на самом деле неправильный. Я предполагал, что у базового класса будут другие дочерние элементы, которые могут иметь совершенно разные реализации. В этом случае вам пришлось бы изменить дочерний метод.
3. TKey и TValue используются для словаря. В некоторых классах словарь хранит единственное значение, в других — список (multimap). так, например, он может хранить {int, MyObject} или {int, IList<MyObject>}. Я предполагаю, что, возможно, я пытаюсь заставить эти классы делать слишком много в этом случае.