Получение исключения при безопасном приведении к общему типу в Котлине - PullRequest
0 голосов
/ 21 ноября 2018

Я использую опцию безопасного приведения в kotlin, т.е. as?, тем не менее, я получаю исключение приведения класса, когда типы данных не совместимы, это происходит, когда я делаю это с помощью универсального метода, написанного для выполнения case, однако, если яПри непосредственном выполнении приведения он возвращает нулевое значение, как и ожидалось, из безопасного приведения

class CastTest(val data: Any) {

   fun castViaGenericMethod(): TypeA? {
      return castToContext<TypeA>()
   }

   fun castDirectly(): TypeA? {
      return data as? TypeA
   }

   private fun <CONTEXT> castToContext(): CONTEXT? = data as? CONTEXT

}

castViaGenericMethod () -> этот метод выдает исключение ClassCastException, когда данные не являются типом TypeA.castDirectly () -> возвращает ноль, если приведение невозможно.

Пожалуйста, предложите, как это можно сделать.

1 Ответ

0 голосов
/ 21 ноября 2018

Чтобы решить вашу проблему, вы можете использовать reified тип :

inline fun <reified CONTEXT> castToContext() = data as? CONTEXT

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

Если мы посмотрим на байт-код, то увидим, что везде, где записан ваш CONTEXT -общий тип, он становится java/lang/Object:

private final castToContext()Ljava/lang/Object;
 L0
  LINENUMBER 12 L0
    ALOAD 0
    GETFIELD CastTest.data : Ljava/lang/Object;
    DUP
    INSTANCEOF java/lang/Object // (1)
    IFNE L1                     // (1)
    POP          // (2)
    ACONST_NULL  // (2)
   L1
    ARETURN
   L2
    LOCALVARIABLE this LCastTest; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

Итакбезопасное приведение фактически делает проверку, не является ли данный объект типа java/lang/Object (1), и устанавливает значение, которое будет возвращено null, если это так.Но так как он имеет тип java/lang/Object, значение просто возвращается как есть.На вызывающей стороне, однако, байт-код выглядит следующим образом:

LINENUMBER 4 L0
ALOAD 0
INVOKESPECIAL CastTest.castToContext ()Ljava/lang/Object; // the call
CHECKCAST TypeA // the type check
ARETURN

Он делает дополнительные CHECKCAST TypeA после вызова castToContext, и там вы получаете ClassCastException, поскольку значение не было обнулено (универсальный типинформация была стерта во время выполнения).

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