Как сделать ссылку или вызвать функцию-член, если эта функция существует - PullRequest
0 голосов
/ 18 мая 2019

Я хочу проверить, что если функция-член с определенным именем существует в объекте, если она вызывает функцию-член или делает ссылку на эту функцию-член.

Здесь у меня нет типаобъекта, т.е. объект, возможно, не реализует никакого интерфейса, но имеет функцию-член cancel ().

Я использовал этот метод (отражение), чтобы проверить, существует ли функция-член, т.е.if (object::class.members.any { it.name == "cancel" }) и когда этот оператор возвращает true, я уверен, что метод существует, но компилятор все еще не уверен, существует ли в объекте метод 'cancel' или нет

fun canceller(object: Any): KFunction<Any>?
{
    var canceller: KFunction<Any>? = null

    // check if object has member function 'cancel'
    if (object::class.members.any { it.name == "cancel" })
    {
        // make reference of that member function and return it
        canceller = object::cancel  //cancel is still not recognized as a member function and gives an error that "Unresolved reference: cancel"

        // or just call it now
        // object.cancel()
    }
    return canceller
}

Я ожидаю, что переменная отмены должна бытьприсваивается value.cancel (), но компилятор не уверен, что функция cancel () существует (с ошибкой «Неразрешенная ссылка: отмена») в объекте даже после того, как мы предоставили проверку внутри оператора if

Ответы [ 2 ]

0 голосов
/ 20 мая 2019

Это не предназначено для такого использования.Reflection - это то, что вы используете, если во время компиляции вы не знаете, с чем имеете дело во время выполнения.Некоторые примеры:

  • вам нужно использовать тип, настроенный в некотором файле свойств (Class.forName("someTypeString").newInstance())
  • вы написали утилиту, которая извлекает содержимое вашего объекта для целей отладки
  • вам нужен доступ к коду, который на самом деле вам не виден (частные поля, к которым вы не можете легко получить доступ, но вам нужно)
  • еще много ... но большинствовремя очень особых случаев использования

Теперь то, что вы показали, является ссылкой на функцию (object::cancel).Чтобы использовать ссылку на функцию, компилятор должен знать тип object, а для этого типа должна существовать cancel -функция.Поскольку object относится к типу Any, а условие if имеет значение только во время выполнения, компилятор не знает, что доступна функция cancel, и поэтому компиляция не удалась.

Примечаниечто если вы не делаете ничего особенного, вам лучше проверить общий тип / интерфейс.Так, например, если ваши объекты реализуют интерфейс Cancellable, вы можете просто изменить свой код на что-то вроде следующего:

fun canceller(object: Any): KFunction<Any>? {
  var canceller: KFunction<Any>? = null

  // check if object is of type Cancellable
  if (object is Cancellable) {
    // make reference of the Cancellable::cancel-function
    canceller = object::cancel  // smart-cast acting

    // or you could also call it directly: object.cancel()
  }
  return canceller
}

или, возможно, вы можете просто сэкономить эту функцию и в итоге получить что-то вроде:

val someObj : Cancellable = ...
// somewhere later:
someObj.cancel()

Отражение довольно дорого, и если вы не совсем уверены, для чего оно полезно, вам не следует его использовать.

Если вы действительно знали, что делаете ...тогда ладно ... конечно, также возможно вызывать эту функцию через отражение, и если вы просите о существовании функции через отражение, вы также должны вызывать ее через отражение:

object::class.members.first {
  // note: I am using just the first function... if there are several, you need to check which one to use (parameter/type)
          it.name == "cancel" 
   }
   .call(object)
0 голосов
/ 18 мая 2019

Я думаю, вы можете использовать отражения для этой цели.

myObject.javaClass.kotlin.members.any {it.name == "cancel"}

И лучший способ выразить идею «объекта, который имеет все переменные» - это определить интерфейс и реализовать все эти объекты

Интерфейс Achiever {val name: String}

...