控制Kotlin DSL生成器中的作用域
我试图为我的范围问题找到完美的解决方案,我真的很想听听你的意见 我有一些无法更改的第三方类:控制Kotlin DSL生成器中的作用域,kotlin,scope,dsl,builder,Kotlin,Scope,Dsl,Builder,我试图为我的范围问题找到完美的解决方案,我真的很想听听你的意见 我有一些无法更改的第三方类: class Employee { var id = 0 var name = "" var card : Card? = null // ... } class Card { var cardId = 0 } 我的目标是培养这样一名员工: val built = employee { id = 5 name = "max" add
class Employee {
var id = 0
var name = ""
var card : Card? = null
// ...
}
class Card {
var cardId = 0
}
我的目标是培养这样一名员工:
val built = employee {
id = 5
name = "max"
addCard {
cardId = 5
}
}
原始bean中没有方法addCard。
因此,我提出了以下构建器:
@DslMarker
@Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
annotation class Scoped
@Scoped
object Builder {
inline fun employee (init: (@Scoped Employee).() -> Unit): Employee {
val e = Employee()
e.init()
return e
}
inline fun Employee.addCard(init: (@Scoped Card).() -> Unit) {
val c = Card()
c.init()
card = c
}
}
不幸的是,现在我得到了一个臭名昭著的错误:
错误:“inline fun Employee.addCard(init:(Scratch_1.Card)。()->Unit):在此上下文中,隐式接收方无法调用Unit”。如有必要,请使用显式
我理解错误的原因,我想考虑解决方案
with(Builder) {
val built = employee {
id = 5
name = "max"
addCard {
employee {
// ...
}
cardId = 5
}
}
}
with(Builder) {
val built = employee {
id = 5
name = "max"
with(this@with) {
this@employee.addCard {
cardId = 5
}
}
}
}
class EmployeeEx : Employee() {
inline fun addCard(init: (@Scoped Card).() -> Unit) {
val c = Card()
c.init()
card = c
}
}
建筑商:
@Scoped
object Builder {
inline fun employee (init: (@Scoped EmployeeEx).() -> Unit): Employee {
val e = EmployeeEx()
e.init()
return e
}
}
那么最好的解决方案是什么?我错过什么了吗? 非常感谢您阅读这篇文章
获取您正在使用的可实现代码,以及@DSLMarker
用于第一种方法不起作用的所有其他情况李>@不推荐(level=ERROR)
val built = employee {
id = 5
name = "max"
addCard {
cardId = 6
}
employee { } // <--- compilable, but does not have sense
}
现在,以下示例不可编译:
val built = employee {
//...
employee { } // <--- compilation error with your message
}
val-builded=employee{
//...
雇员{}//
您可以在不创建新类的情况下进行定义,
它也适用于外国不可接触的来源:
有两种经典工具可以控制dsl范围:
@DSLMarker
获取您正在使用的可实现代码,以及
@不推荐(level=ERROR)
用于第一种方法不起作用的所有其他情况
例如,当前可以构建嵌入式员工:
val built = employee {
id = 5
name = "max"
addCard {
cardId = 6
}
employee { } // <--- compilable, but does not have sense
}
现在,以下示例不可编译:
val built = employee {
//...
employee { } // <--- compilation error with your message
}
val-builded=employee{
//...
employee{}/我将提供以下设计,它非常经典,生成的代码很短
由于Builder
增加了额外的作用域并阻止了丑陋的导入,我们只需通过和构造停止使用它,并重载调用操作符即可
对可编辑代码使用@DslMarker
,对外来代码使用@Deprecated
,以控制范围
@作用域
对象生成器{
运算符fun invoke(init:BuildingContext.(->Unit)=BuildingContext().init()
}
@范围
类构建上下文{
有趣的员工(init:employee.(->Unit)=employee()。应用{init()}
fun Employee.addCard(init:Card.(->Unit)=运行{Card=Card()。应用{init()}
@已弃用(level=DeprecationLevel.ERROR,message=“此处禁止员工”)
fun Employee.Employee(init:(@Scoped Employee)。()->Unit){
@已弃用(level=DeprecationLevel.ERROR,message=“此处禁止使用卡片”)
有趣的卡片.addCard(init:(@Scoped Card)。()->Unit){
}
趣味主线(args:Array){
建筑商{
val=employee{
//employee{}我将提供以下设计,它非常经典,并且生成的代码很短
由于Builder
增加了额外的作用域并阻止了丑陋的导入,我们只需通过和构造停止使用它,并重载调用操作符即可
对可编辑代码使用@DslMarker
,对外来代码使用@Deprecated
,以控制范围
@作用域
对象生成器{
运算符fun invoke(init:BuildingContext.(->Unit)=BuildingContext().init()
}
@范围
类构建上下文{
有趣的员工(init:employee.(->Unit)=employee()。应用{init()}
fun Employee.addCard(init:Card.(->Unit)=运行{Card=Card()。应用{init()}
@已弃用(level=DeprecationLevel.ERROR,message=“此处禁止员工”)
fun Employee.Employee(init:(@Scoped Employee)。()->Unit){
@已弃用(level=DeprecationLevel.ERROR,message=“此处禁止使用卡片”)
有趣的卡片.addCard(init:(@Scoped Card)。()->Unit){
}
趣味主线(args:Array){
建筑商{
val=employee{
//员工{}好的,我想我现在有了一个很好的概述
首先,我认为问题的原因是构建器对象上的IScope。当删除它时,它工作正常。
但是,它仍然允许使用“非法”语法:
解决方案
只在生成器对象中保留扩展方法,不要在后者上添加注释
就我而言,我必须介绍另一个建筑商来开始施工
object EmployeBuilder {
}
object Builder {
inline fun EmployeBuilder.employe(init: (@Scoped Employee).() -> Unit): Employee {
val e = Employee()
e.init()
return e
}
inline fun Employee.addCard(init: (@Scoped Card).() -> Unit) {
val c = Card()
c.init()
card = c
}
}
fun main() {
with(Builder) {
val built = EmployeBuilder.employe {
id = 5
name = "max"
addCard {
cardId = 5
}
}
}
}
现在我们有了它:
不会“污染”类上下文,因为扩展方法仅在生成器对象中可用
不能使用非法语法,因为所有参数都被DslMarker注释锁定
好的,我想我现在有一个很好的概述
首先,我认为问题的原因是构建器对象上的IScope。当删除它时,它工作正常。
但是,它仍然允许使用“非法”语法:
解决方案
只在生成器对象中保留扩展方法,不要在后者上添加注释
就我而言,我必须介绍另一个建筑商来开始施工
object EmployeBuilder {
}
object Builder {
inline fun EmployeBuilder.employe(init: (@Scoped Employee).() -> Unit): Employee {
val e = Employee()
e.init()
return e
}
inline fun Employee.addCard(init: (@Scoped Card).() -> Unit) {
val c = Card()
c.init()
card = c
}
}
fun main() {
with(Builder) {
val built = EmployeBuilder.employe {
id = 5
name = "max"
addCard {
cardId = 5
}
}
}
}
现在我们有了它:
没有类上下文的“污染”,因为扩展
object EmployeBuilder {
}
object Builder {
inline fun EmployeBuilder.employe(init: (@Scoped Employee).() -> Unit): Employee {
val e = Employee()
e.init()
return e
}
inline fun Employee.addCard(init: (@Scoped Card).() -> Unit) {
val c = Card()
c.init()
card = c
}
}
fun main() {
with(Builder) {
val built = EmployeBuilder.employe {
id = 5
name = "max"
addCard {
cardId = 5
}
}
}
}