如何使用泛型获取枚举的值?

时间:2018-11-30 19:08:11

标签: generics kotlin

我想提供此问题的上下文。我见过独特的解决方案,人们可​​以创建从SharedPreferences而不是后备字段读取/写入的委托。为此,例如:

class SharedPrefsString(private val sharedPrefs: SharedPreferences) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
        return sharedPrefs.getString(property.name, "")
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
        sharedPrefs.edit().putString(property.name, value).apply()
    }
}

var myString: String by SharedPrefsString(myPrefs)

但是,我希望我可以对通用枚举做同样的事情,因为所有枚举都有一个valueOf(string)方法,但是下面的方法不起作用。我在评论中放了一些我尝试过的东西:

class SharedPrefsEnum<T : Enum<T>>(private val sharedPrefs: SharedPreferences) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        // Doesn't work, can't reference T, which makes sense. 
        // return T.valueOf(sharedPrefs.getString(property.name, ""))

        // Can't use reified type here, which makes sense.
        // return enumValueOf<T>(sharedPrefs.getString(property.name, ""))
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        sharedPrefs.edit().putString(property.name, value.name).apply()
    }
}

var myEnum: MyEnum by SharedPrefsEnum(myPrefs)

像这样可能吗?

3 个答案:

答案 0 :(得分:6)

以您的答案为基础,可以避免使用enumConstants属性的反射:

class SharedPrefsEnum<T : Enum<T>>(
    private val sharedPrefs: SharedPreferences, 
    private val clazz: Class<T>
) : ReadWriteProperty<Any, T> {
    operator fun getValue(thisRef: Any, property: KProperty<*>): T {
        val enumName = sharedPrefs.getString(property.name, "")
        return clazz.enumConstants.find { it.name == enumName }!!
    }

    operator fun setValue(thisRef: Any, property: KProperty<*>, value: T) {
        sharedPrefs.edit().putString(property.name, value.name).apply()
    }
}

然后,您可以使用以下方法轻松添加代表:

inline fun <reified T : Enum<T>> sharedPreferences(prefs: SharedPreferences) = 
    SharedPrefsEnum(prefs, T::class.java)

允许您为其分配:

private var myEnum: MyEnum by sharedPreferences(preferences)

您可能希望使属性类型可为空,就像您的SharedPreferences不包含该值一样,这将在访问该值时引发异常。

答案 1 :(得分:2)

我能够使用反射解决此问题。感谢佐伊为我指明了正确的方向。

我也必须为枚举传递类,但是使用它我可以使用反射找到valueOf并使用从首选项中获得的字符串进行调用。

class SharedPrefsEnum<T : Enum<T>>(private val sharedPrefs: SharedPreferences, private val clazz: Class<T>) {
    operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
        val prefsString = sharedPrefs.getString(property.name, "")
        val method = clazz.getDeclaredMethod("valueOf", String::class.java)
        return method.invoke(null, prefsString) as T
    }

    operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
        sharedPrefs.edit().putString(property.name, value.name).apply()
    }
}

答案 2 :(得分:1)

我正在使用这个

Right

这是实现:

var lastUpdate by PersistedProperty("lastUpdate",0L)