Как наследовать универсальный класс от вложенного универсального класса в C#
Я делал свою домашнюю работу и застрял в некоторых проблемах с дженериками и наследованием.
У меня есть общий класс красно-черного дерева, так как это красно-черное дерево, его ключи должны быть сопоставимы, поэтому
public class RedBlackTree<T> where T : IComparable<T>
И затем я хочу другой класс, скажем, интервальное дерево, которое является расширенной версией красно-черного дерева. Итак, я определил интервал следующим образом:
public class Interval<T> : IComparable where T : IComparable<T>
и так как дерево интервалов действительно является красно-черным деревом с интервалами в качестве ключей, но только с более конкретными методами, я определил класс следующим образом:
public class IntervalTree<T> : RedBlackTree<Interval<T>> where T : IComparable<T>
Но это не позволит мне сделать это, он говорит что-то вроде "не может неявно преобразовать Interval<T>
в System.IComparable<Interval<T>>
", но я тоже не могу написать что-то вроде where Interval<T> : IComparable<Interval<T>>
,
Как бы я делал такие вещи в C#, или если нет способа сделать это наследование в C#, какие другие шаблоны я должен использовать?
2 ответа
Давайте разберем это. Мы прекратим использовать T для всего, потому что это сбивает с толку.
class RedBlackTree<RBTValue> where RBTValue : IComparable<RBTValue>
ОК, так что каждое RBTValue, которое используется для создания RedBlackTree<>
должен быть IComparable<RBTValue>
,
Вы хотите сказать
RedBlackTree<Interval<T>>
для некоторых T
в какой-то момент. Что мы тогда знаем? Interval<T>
используется для RBTValue
, и поэтому Interval<T>
должно быть известно, что IComparable<Interval<T>>
,
Поэтому определение Interval<>
должно быть:
class Interval<IValue> : IComparable<Interval<IValue>>
Теперь, это также тот случай, когда любой IValue
должно быть IComparable<IValue>
? Если да, то нам нужно ограничение:
class Interval<IValue> : IComparable<Interval<IValue>>
where IValue : IComparable<IValue>
Убедитесь, что это ясно. Это говорит о двух вещах: (1) что интервал сопоставим с другим интервалом, и (2) что значения в интервале сопоставимы с другими значениями.
Теперь мы хотим определить интервальное дерево.
class IntervalTree<ITValue> : RedBlackTree<Interval<ITValue>>
where ITValue : IComparable<ITValue>
Удовлетворяет ли это наши потребности? Interval<IValue>
требует, чтобы IValue
воплощать в жизнь IComparable<IValue>
, ITValue
инвентарь IComparable<ITValue>
через ограничение, поэтому требование выполнено.
RedBlackTree<RBTValue>
требует, чтобы RBTValue
быть IComparable<RBTValue>
, Interval<ITValue>
инвентарь IComparable<Interval<ITValue>>
так что это тоже хорошо, и мы все готово.
Это все говорит: вы могли бы рассмотреть вместо реализации IntervalTree<>
с RBT в качестве члена, а не в качестве базового класса. Был ли когда-нибудь случай, когда вы будете полиморфно обрабатывать интервальные деревья с помощью красных черных деревьев? Если нет, то нет необходимости раскрывать детали реализации на публичной поверхности.
Наконец, такие типы могут быть очень запутанными. Чтобы узнать больше о том, каким образом можно использовать этот шаблон гораздо более ужасно, см.
https://blogs.msdn.microsoft.com/ericlippert/2011/02/03/curiouser-and-curiouser/
Вы получаете следующую ошибку:
Ошибка компиляции (строка xx, col yy): тип "Program.Interval
" нельзя использовать в качестве параметра типа "T" в универсальном типе или методе "Program.RedBlackTree ". Не существует неявного преобразования ссылок из 'Program.Interval ' в 'System.IComparable >'.
Вам нужно разобрать ошибку и подумать о том, что она говорит вам. В этом случае вы заявляете, что IntervalTree
наследуется от RedBlackTree<Interval<T>>
, Тем не менее, вы указали, что общий T
тип для RedBlackTree
должен реализовать IComparable<T>
, Если вы реализуете IComparable
за Interval
ошибка исчезнет. Interval
должен реализовывать интерфейс, используемый для ограничения RedBlackTree
,