Ввод / вывод дженериков для абстрактного контейнерного инструмента в Котлине?

Я создаю абстрактный класс инструмента, который работает на другом наборе иностранных классов (не контролируемых мной). Иностранные классы концептуально схожи в определенных точках интерфейса, но имеют различный синтаксис для доступа к их сходным свойствам. Они также имеют различный синтаксис для применения результатов операций инструмента. Я создал класс данных с внутренними классами, основанный на этом ответе от @hotkey .

Вот проблема с дженериками: иностранные классы являются в основном контейнерами элементов. Тип контейнера каждого класса отличается. Некоторые из контейнеров имеют фиксированный тип элемента, в то время как другие контейнеры несут общий тип элемента. У меня возникают проблемы с применением концепций дженериков in vs. out , ковариации и контравариантности к этой модели. Вот упрощенный пример, используя slicing CharSequence и List, который почти точно сравнивается с проблемой в отношении дженериков:

 // *** DOES NOT COMPILE *** data class Slicer<C,E>(val obj: C, val beg: Int, val end: Int) { // C is container type; E is element type // but unsure how to apply in/out properly inner abstract class SObj<C,E>{ abstract val len: Int // an input that tool requires abstract val sub: C // an output of tool (container) abstract val one: E // an output of tool (element) inner class TCsq(val c: CharSequence): SObj<C,E>() { override val len get()= c.length override val sub get()= c.substring(adjusted) // PROBLEM override val one get()= c[finder+5] // PROBLEM } inner class TList<E>(val l: List<E>): SObj<C,E>() { override val len get()= l.size override val sub get()= l.slice(adjusted) // PROBLEM override val one get()= l[finder] // PROBLEM } // sample ops use both data class vals and abstract properties val adjusted get()= (beg+1)..(len-1) val finder get()= (end-beg)/2 } } 

Как правильно подать заявку / сюда, чтобы сделать эту работу? В качестве альтернативы, если это не самая лучшая конструкция, как еще это можно структурировать?

NB Имейте в виду, что CharSequence и List представляют собой иностранные классы, которые не могут быть изменены, а adjusted и finder являются образцами многих операций, которые инструмент выполняет в классах. В настоящее время операции инструмента просто засоряются вокруг базы кода внутри (или как расширения) различных контейнеров повторяющимся и неравномерным образом.

Если я правильно понял вопрос, дисперсия здесь не имеет значения, вы просто ошиблись:

 inner class TCsq(val c: CharSequence): SObj<CharSequence, Char>() 

а также

 inner class TList<E>(val l: List<E>): SObj<List<E>,E>() 

То, что вы не можете сделать таким образом, – это операции, которые «меняют E »: для этого требуются более высокосортные типы, которые Kotlin не поддерживает.