有没有办法限制DSL中的扩展方法?
假设我有这样的类结构:
class Outer {
fun middle(op: Middle.() -> Unit): Middle {
val middle = Middle()
middle.op()
return middle
}
}
class Middle {
fun inner(op: Inner.() -> Unit): Inner {
val inner = Inner()
inner.op()
return inner
}
}
class Inner
fun outer(op: Outer.() -> Unit): Outer {
val outer = Outer()
outer.op()
return outer
}
然后我可以像这样创建一个调用:
outer {
middle {
inner {
middle { } // Here is the problem
}
}
}
我的问题是标记的middle { }
调用是令人困惑的,因为当它看起来像是在添加到Middle
时它向Outer
添加了Inner
。
有没有办法不允许middle { }
电话?
您可以使用deprecated
的变通方法:
class Outer {
fun middle(op: Middle.() -> Unit): Middle {...}
@Deprecated("can not be used inside a Outer block", level = DeprecationLevel.ERROR)
fun outer(op: Outer.() -> Unit): Outer = TODO()
}
class Middle {
fun inner(op: Inner.() -> Unit): Inner {...}
@Deprecated("can not be used inside a Middle block", level = DeprecationLevel.ERROR)
fun middle(op: Middle.() -> Unit): Middle = TODO()
}
class Inner {
@Deprecated("can not be used inside a Inner block", level = DeprecationLevel.ERROR)
fun inner(op: Inner.() -> Unit): Inner = TODO()
}
现在编译器会给你一个错误,IDE在完成时不会建议错误的函数:
outer {
middle {
inner {
middle { } // error
}
}
}
但你真的不应该为大型DSL做这件事。最好像@KirillRakhman建议的那样等待https://youtrack.jetbrains.com/issue/KT-11551。
编辑:修好我的例子后,它变小了。对于一个类有一个虚函数,毕竟它不是那么多的样板。
限制范围的官方方式是DslMarker。在某些情况下(例如,当你需要注释java源代码时)它无能为力 - 而且这里使用的是@Deprecated
。但首先尝试DslMarker
。
@DslMarker
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
annotation class Scope
@Scope
class Outer {
fun middle(op: Middle.() -> Unit): Middle { /**/ }
}
@Scope
class Middle {
fun inner(op: Inner.() -> Unit): Inner {/**/ }
}
class Inner
因此,最后一次中间呼叫不再可编译。