Как использовать все подклассы запечатанного класса для обработки экземпляра подкласса? - PullRequest
0 голосов
/ 30 октября 2019

Я пытаюсь использовать новую функцию sealedSubclasses в Kotlin на практике. Мне нужно обработать экземпляр некоторых подклассов из запечатанного класса, но я не знаю ранее, какой это подкласс, поэтому обычная процедура - попробовать все подклассы.

Предположим, что существует 20 или более подклассов.

Ниже я упростила это, чтобы было легко следовать. Я использовал только 2 подкласса со скалярными внутренними типами. В реальном мире могут быть сложные типы объектов.

sealed class Person {
  abstract var name:String
     // ...
}

data class Doctor(      
  var license: String = "",   
    // ....
  override var name:String = ""
) : Person()

// ....
data class Fireman ( 
  var medals: Int=0, 
  // ....   
  override var name:String = ""
) : Person()

Теперь мне нужно клонировать эту структуру: Сначала попробуйте:

var p:Person = Doctor("123","Louis")
var q:Person
  // ...
Person.copy  // it is forbidden

Итак, мне нужно сделать

var p:Person = Doctor("123","Louis")
var q:Person
when (p) {
is Doctor -> q = p.copy()   
   // ...
is Fireman -> q = p.copy()
}   

Обратите внимание, что это плохой код,потому что всегда, что я добавляю новый подкласс, я должен добавить вручную в процессе клонирования, повторяя субблок.

Поэтому я пытаюсь использовать sealedSubclasses, но мне не удалось соединить подкласс с типом для имитации предыдущего кода

for (subClass в Token :: class.sealedSubclasses) {if (ele :: class.simpleName as String == производное.qualifiedName) {// ?????? }}

Что я могу сделать?

Ответы [ 3 ]

1 голос
/ 30 октября 2019

Если хотите, вы можете сделать это с помощью размышлений, но я не думаю, что sealedSubclasses будет полезно. Примерно (не проверено):

fun copy(p: Person, name: String) {
   val copyMethod = p::class.memberFunctions().find { it.name == "copy" }!!
   val params = copyMethod.parameters
   val receiverParam = params[0]
   val nameParam = params.find { it.name == "name" }!!
   return copyMethod.callBy(mapOf(receiverParam to p, nameParam to name))
}

Конечно, применяются обычные предостережения с ненадежностью и эффективностью отражения.

1 голос
/ 30 октября 2019

Одним из решений вашей проблемы было бы создание собственной реализации абстрактного метода copy():

sealed class Person {
    abstract val name: String
}

data class Doctor(
    override val name: String,
    val license: String,
    val extraProperty: Any
) : Person()

data class Fireman(
    override var name: String,
    val medals: Int
) : Person()

val p: Person = Doctor("123", "Louis", "extra")
var q: Person = when (p) {
    is Doctor -> p.copy(name = "New name", license = "Other license", extraProperty = "extra2")
    is Fireman -> p.copy(name = "New Name", medals = 15)
    // And so on...
}

У кого-то возникла проблема, аналогичная вашей в этом посте https://stackoverflow.com/a/47624138/3542143

0 голосов
/ 31 октября 2019

Я думаю, вы можете использовать обобщенные значения, если вы используете пустые аргументы для вызова copy(). (На моем телефоне, пожалуйста, извините за любые проблемы с синтаксисом здесь.)

class Person <out T: Person> {
    abstract var name: String
    abstract fun unchangedCopy(): T
}

data class Unemployed (
    override var name: String
): Person<Unemployed>() {
    override fun unchangedCopy() = copy()
}

var p:Person = Unemployed(“John”)
var q:Person = p.unchangedCopy()

Это заставит вас переопределить unchangedCopy в каждом новом подклассе, так что нечего забывать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...