Проблема генерических свойств Котлина

У меня возникли проблемы с Kotlin при переводе моего проекта андроида из java в Kotlin. Скажем, у меня есть интерфейс I и интерфейс O, который расширяет интерфейс I.

interface I{ } interface O: I{ } 

И общий класс A, который имеет общий параметр V, который расширяет интерфейсI, и общий класс B, который расширяет класс A:

 abstract class A<V: I> { } class B : A<O>() { } 

Когда я пытаюсь создать такое свойство:

 val returnB: A<I> get() = b 

Я получаю ошибку компилятора 'required A, найденный B'. В Java это будет работать без каких-либо проблем. Как я могу получить доступ к этому с помощью Kotlin?

Мне нужно использовать этот подход для базовых классов в моем приложении.

BaseViewModel, которые имеют общий параметр для класса Navigator:

 abstract class BaseViewModel<N>(application: Application, val repositoryProvider: RepositoryProvider) : AndroidViewModel(application) { var navigator: N? = null fun onDestroyView() { navigator = null } open fun onViewAttached() { } } 

Класс BaseActivity:

 abstract class BaseActivity<T : ViewDataBinding, V : BaseViewModel<BaseNavigator>> : AppCompatActivity(), BaseFragment.Callback, BaseNavigator { // ....... private var mViewModel: V? = null /** * Override for set view model * @return view model instance */ abstract val viewModel: V // ....... } 

Интерфейс BaseNavigator использует для VM – Просмотр связи:

 interface BaseNavigator { fun invokeIntent(intent: Intent?, b: Bundle?, c: Class<*>?, forResult: Boolean, requestCode: Int) fun replaceFragment(fragment: Fragment, addToBackStack: Boolean) fun showDialogFragment(fragment: DialogFragment?, tag: String?) fun showToast(message: String?) } 

Вот пример кода, где я расширяю эти классы:

AuthViewModel:

 class AuthViewModel(context: Application, repositoryProvider: RepositoryProvider) : BaseViewModel<AuthNavigator>(context,repositoryProvider) { // .... } 

AuthNavigator:

 interface AuthNavigator : BaseNavigator { fun requestGoogleAuth(code: Int) fun requestFacebookAuth(callback: FacebookCallback<LoginResult>) } 

И класс AuthActivity, где появилась ошибка:

 class AuthActivity : BaseActivity<ActivityAuthBinding, BaseViewModel<BaseNavagator>>(), GoogleApiClient.OnConnectionFailedListener, AuthNavigator { @Inject lateinit var mViewModel: AuthViewModel override val viewModel: BaseViewModel<BaseNavigator> get() = mViewModel // Required:BaseViewModel<BaseNavigator> Found: AuthViewModel 

}

Я также пытаюсь изменить общий параметр в AuthActivity от BaseViewModel до AuthViewModel, но компилятор выдает ошибку «необходимый BaseViewModel».

 And i tried to change override val viewModel: BaseViewModel<BaseNavigator> get() = mViewModel to override val viewModel: AuthViewModel get() = mViewModel 

но в этом случае компилятор выдает ошибку «Тип свойства – это« AuthViewModel », который не является типом подтипа переопределенного».

update: Это работает, когда я добавляю свойство в BaseViewModel:

 BaseViewModel<out N : BaseNavigator> 

Но в этом случае я могу только создать

 private var navigator: N? = null 

который я должен быть общедоступным, поэтому я могу установить его в классе Activity. Могу ли я создать публичный сеттер для этого свойства? Когда я пытаюсь создать сеттер, возникает ошибка:

 private var navigator: N? = null fun setNavigator(n: N) { // error: Type parameter N is declared as 'out' but occurs in 'in' position in type N navigator = n } 

    Похоже, вы ожидаете, что параметр типа будет вести себя ковариантно . Kotlin использует дисперсию объявления-сайта. Если вы не укажете дисперсию, параметры универсального типа являются инвариантными .

    Другими словами, прямо сейчас нет связи между A<I> и A<O> . Но если вы заявляете

     abstract class A<out V : I> 

    то A<O> является подтипом A<I> .

    (Существует также <in> для контравариантности, которая работает наоборот. Подробнее см. https://kotlinlang.org/docs/reference/generics.html .)

    Intereting Posts