@nhaarman 的答案很接近,但如果被绑定的类实际上不是视图的类型,则会留下漏洞。
这个演员阵容并不是一件坏事,如果有的话,也没有很多好的答案。你总是可以添加一个断言来给出一个非常直接的错误消息,因为这些会在创建活动时立即发生,你会在测试的早期看到错误
如果不创建将关系的所有部分作为一个整体来管理的东西,我认为您不会轻易获得更好的答案。我认为他的回答风险很小。
编译时检查以避免运行时错误
你可以编写一个函数,在编译时检查缺失的部分,人们可以像编译时断言一样使用它。
// a function that is used when people want to check validity at compile time,
// it does nothing but cause compiler error if wrong heirarchy
fun <A: V, P: Presenter<V>, V : View> checkValid() {
// empty on purpose, used for compile time check
}
// successful:
checkValid<FolderChooserActivity, FolderPresenter, FolderChooserView>()
// error below: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.FolderChooserView'"
checkValid<TryingToFoolItActivity, FolderPresenter, FolderChooserView>()
// this is blocked because SomeOtherActivity has its own compiler error so SomeOtherActivity type is not fully known
checkValid<SomeOtherActivity, FolderPresenter, FolderChooserView>()
使用函数创建类,并带有编译时检查以避免运行时错误
您还可以要求使用函数来构造*Activity 类。但是如果你不能强制人们确保他们拥有正确的视图基类,你就不能强制使用这个函数。无论如何,只是为了给这个问题更多的想法。
inline fun <reified A: V, P: Presenter<V>, V : View> makeActivity(): A {
return A::class.java.newInstance()
}
// successful:
val good1 = makeActivity<FolderChooserActivity, FolderPresenter, FolderChooserView>()
// error below: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.FolderChooserView'"
val bad1 = makeActivity<TryingToFoolItActivity, FolderPresenter, FolderChooserView>()
完整代码:
我将完整的代码放在这里,以便我可以对此进行更多探索并尝试获得替代的完整答案。这实际上只是@nhaarman 答案的一种变体。
// sample classes
class FolderPresenter : Presenter<FolderChooserView>() { }
class BadPresenter : Presenter<RandomView>() { }
// successful declaration
class FolderChooserActivity : BaseActivity<FolderPresenter, FolderChooserView>(), FolderChooserView { }
// Error: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.Presenter<test.renlearn.solrpref.FolderChooserView>'"
class SomeOtherActivity : BaseActivity<BadPresenter, FolderChooserView>(), FolderChooserView {}
// Runtime error, we are not a FolderChooserView
class TryingToFoolItActivity : BaseActivity<FolderPresenter, FolderChooserView>() {}
// now the version using a function to construct the activity, where
// this function adds the missing step of compiler time validation.
inline fun <reified A: V, P: Presenter<V>, V : View> makeActivity(): A {
return A::class.java.newInstance()
}
// or a function that is used when people want to check validity at compile time,
// it does nothing but cause compiler error if wrong heirarchy
fun <A: V, P: Presenter<V>, V : View> checkValid() {
// empty on purpose, used for compile time check
}
public fun foo() {
// successful:
val good1 = makeActivity<FolderChooserActivity, FolderPresenter, FolderChooserView>()
// error below: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.FolderChooserView'"
val bad1 = makeActivity<TryingToFoolItActivity, FolderPresenter, FolderChooserView>()
// this is blocked because SomeOtherActivity has its own compiler error so SomeOtherActivity type is not fully known
val bad2 = makeActivity<SomeOtherActivity, FolderPresenter, FolderChooserView>()
// successful:
checkValid<FolderChooserActivity, FolderPresenter, FolderChooserView>()
// error below: "Kotlin: Type argument is not within its bounds: should be subtype of 'test.so.FolderChooserView'"
checkValid<TryingToFoolItActivity, FolderPresenter, FolderChooserView>()
// this is blocked because SomeOtherActivity has its own compiler error so SomeOtherActivity type is not fully known
checkValid<SomeOtherActivity, FolderPresenter, FolderChooserView>()
}