代码之家  ›  专栏  ›  技术社区  ›  AdamMc331

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

  •  3
  • AdamMc331  · 技术社区  · 6 年前

    我想提供这个问题的背景。我看到了独特的解决方案,人们创建的代理将从共享的引用中读/写,而不是从支持字段中读/写。要对字符串执行此操作,例如:

    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 回复  |  直到 6 年前
        1
  •  6
  •   Kevin Coppock    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 不包含值,这将在访问值时引发异常。

        2
  •  2
  •   AdamMc331    6 年前

    我可以通过思考来解决这个问题。谢谢佐伊指点我的方向。

    我也必须为枚举传入类,但使用它我可以找到 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()
        }
    }
    
        3
  •  1
  •   Raymond Arteaga    6 年前

    我用这个:

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

    这就是实现:

    class PersistedProperty<T>(var prefName:String, var default: T)
    {
        operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
            return value!!
        }
    
        operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T){
            this.value=value
        }
    
        fun getFresh():T
        {
            value = getPreference(prefName, default)
            return value!!
        }
    
        var value:T? = null
            get(){
                if(field==null)
                    field=getPreference(prefName, default)
                return field
            }
            set(value){
                if(value==field)
                    return
                savePreference(prefName, value)
                field=value
            }
    
    }
    
    fun<T> savePreference(name:String, value:T,prefFile: String? = null)
    {
        val sharedPreferences = App.instance.getSharedPreferences(prefFile?:App.instance.packageName+ "_preferences",Context.MODE_PRIVATE)
        when(value)
        {
            is String->sharedPreferences.edit().putString(name, value).apply()
            is Int->sharedPreferences.edit().putInt(name, value).apply()
            is Long->sharedPreferences.edit().putLong(name, value).apply()
            is Float->sharedPreferences.edit().putFloat(name, value).apply()
            is Boolean->sharedPreferences.edit().putBoolean(name, value).apply()
            else -> throw(Exception("Not suported type"))
        }
    }