[英]How to implement property delegate that works with an arbitrary type
I'm trying to implement custom property delegate to store props in a Map (just like in docs , for the educational purposes)我正在尝试实现自定义属性委托以将道具存储在 Map 中(就像在docs中一样,出于教育目的)
Delegate implementation must:委托实施必须:
I've wrote a code that satisfies first condition:我写了一个满足第一个条件的代码:
import kotlin.reflect.KProperty
fun main() {
val e = Example(PropInMapDelegate())
e.myProp = 1;
println(e.myProp) // e.myProp is "Any?" :(
}
class Example(propInMapDelegate: PropInMapDelegate) {
var myProp by propInMapDelegate
}
class PropInMapDelegate {
private val _map: HashMap<String, Any?> = HashMap()
operator fun getValue(thisRef: Any, property: KProperty<*>): Any? {
return _map[property.name]
}
operator fun setValue(thisRef: Any, property: KProperty<*>, value: Any?) {
_map[property.name] = value
}
}
But, it has obvious 2 issues:但是,它有两个明显的问题:
var myProp: Int by propInMapDelegate
leads to errors: var myProp: Int by propInMapDelegate
会导致错误:error#1错误 #1
Property delegate must have a 'getValue(Example, KProperty*>)' method. None of the following functions are suitable.
getValue(Any?, KProperty<*>) defined in PropInMapDelegate
error#2错误#2
Property delegate must have a 'setValue(Example, KProperty*>, Int)' method. None of the following functions are suitable.
setValue(Any?, KProperty<*>, Any?) defined in PropInMapDelegate
I've tried to employ generics to allow for type inference, but failed.我尝试使用 generics 来进行类型推断,但失败了。
Changing PropInMapDelegate
implementation like so:像这样更改PropInMapDelegate
实现:
class PropInMapDelegate {
private val _map: HashMap<String, Any?> = HashMap()
operator fun <T>getValue(thisRef: Any, property: KProperty<*>): T? {
return _map[property.name] as T // That feels very wrong
}
operator fun <T>setValue(thisRef: Any, property: KProperty<*>, value: T?) {
_map[property.name] = value
}
}
And using the following并使用以下
class Example(propInMapDelegate: PropInMapDelegate) {
var myProp: Int by propInMapDelegate // error (see below)
}
Leads to: error#1导致:错误#1
Property delegate must have a 'getValue(Example, KProperty*>)' method. None of the following functions are suitable.
getValue(Any, KProperty<*>) where T = Int for operator fun <T> getValue(thisRef: Any, property: KProperty<*>): T? defined in PropInMapDelegate
error#2错误#2
Property delegate must have a 'setValue(Example, KProperty*>, Int)' method. None of the following functions are suitable.
setValue(Any, KProperty<*>, Int?) where T = Int for operator fun <T> setValue(thisRef: Any, property: KProperty<*>, value: T?): Unit defined in PropInMapDelegate
Questions:问题:
as
too, so it's probably ok?编辑:似乎原始实现也使用as
它,所以它可能没问题?public inline operator fun <V, V1 : V> MutableMap<in String, out @Exact V>.getValue(thisRef: Any?, property: KProperty<*>): V1 =
@Suppress("UNCHECKED_CAST") (getOrImplicitDefault(property.name) as V1)
I think the error message is misleading you because of the way it is worded.我认为错误消息的措辞方式误导了您。 "Example" isn't the part that doesn't match. “示例”不是不匹配的部分。 Since Example
is a subtype of Any
, that part of your getValue()
function signature is fine.由于Example
是Any
的子类型,因此您的getValue()
function 签名的那部分很好。
The part that doesn't match is that you are returning T?
不匹配的部分是您要返回T?
but you're trying to use it for a non-nullable property.但您正试图将它用于不可为 null 的属性。
If you change your property to be nullable, it will work:如果您将属性更改为可为空,它将起作用:
var myProp: Int? by propInMapDelegate
Or if you change your operator function to return a non-nullable, it will work:或者,如果您将运算符 function 更改为返回不可为 null 的值,它将起作用:
operator fun <T> getValue(thisRef: Any, property: KProperty<*>): T {
return _map[property.name] as T
}
Note that casting as T
will fail if the value for that key doesn't exist in the map and you're using this for a non-nullable property, because null
cannot be cast to a non-nullable T.请注意,如果 map 中不存在该键的值并且您将其用于不可为 null 的属性,则转换as T
将失败,因为null
无法转换为不可为 null 的 T。
Regarding your question marked 3: As you can see in the standard library source code, casting is unavoidable if you are using a map of arbitrary value types.关于标记为 3 的问题:如您在标准库源代码中所见,如果您使用任意值类型的 map,则强制转换是不可避免的。 It's part of the potential danger in using a map for this purpose.这是为此目的使用 map 的潜在危险的一部分。 It is also possible the map doesn't have the values at all that match up with the requested property names.也有可能 map 根本没有与请求的属性名称匹配的值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.