Search code examples
flutterdartandroid-studio

What should I do? Dart warning: Unnecessary cast. but If I don't do this, my code will fail. its happend when jsonlist convert to List<T>


When I use Flutter(dart) to develop a platform app in Android Studio, I want to encapsulate a general json to any type List tool(_fromJsonList). Below is my lowest level conversion function and type definition code.

// services/api_service.dart
import 'package:dio/dio.dart';
import 'package:myapp/models/Common.dart';
import 'dart:convert';

import 'package:logging/logging.dart';

class ApiService {
  static final ApiService instance = ApiService._internal();

  ……somecode

  // parse JsonList to List<T>
  List<T> _fromJsonList<T extends BaseData>(dynamic data, T entity) {
    if (data != null && data is List) {
      return data.map((e) {
        if (e is Map<String, dynamic>) {
          return entity.fromJson(e);
        } else {
          return e as T;
        }
      }).toList() as List<T>;
    } else {
      return [];
    }
  }
}

class ApiResult<T> {
  ……
}

abstract class BaseData {
  BaseData fromJson(Map<String, dynamic> json);
}

class CommonOption extends BaseData {
  String label;
  String value;

  CommonOption({required this.label, required this.value});

  factory CommonOption.fromJson(Map<String, dynamic> json) {
    return CommonOption(
      label: json['label'],
      value: json['value'],
    );
  }

  @override
  BaseData fromJson(Map<String, dynamic> json) {
    return CommonOption(
      label: json['label'],
      value: json['value'],
    );
  }
}

Call Function:

  Future<List<CommonOption>> getCategoryList() async {
    return await ApiService.instance.getList<CommonOption>(
        '/category/getCategoryList', CommonOption(label: "", value: ""));
  }

When I use as T for type conversion in the conversion function, it will show a yellow warning and [Document Link]:https://dart.dev/tools/diagnostic-messages?utm_source=dartdev&utm_medium=redir&utm_id=diagcode&utm_content=unnecessary_cast#unnecessary_cast like this:

Unnecessary cast warning image

but this does not affect the operation of the code, and the code can be successfully converted; but if I do not use as T twice for type conversion, an error will be reported when the code is running

Unhandled Exception: type 'List(maybe List, it depends on which as T you delete) ' is not a subtype of type 'List' in type cast

Yes, I must use as T twice, and one less will result in an error! What is going on? Can anyone tell me how to eliminate this yellow warning? Or how to encapsulate this tool without triggering a warning?


Solution

  • Your code isn't really solving the json deserialization in an efficient way.

    First, to answer your specific question: if you add entity.fromJson(e) as T the map will return T in all codepaths which does not require toList() to be casted to List<T> anymore.

    Now, more comments about the code:

    fromJson should only be a factory, not an instance method. You are passing a random entity of a certain type T just to use its fromJson. You can pass a T Function(Map<String, dynamic>) fromJson instead:

      List<T> _fromJsonList<T>(dynamic data, T Function(Map<String, dynamic>) fromJson) {
        if (data != null && data is List) {
          // If data is a well-formed json, `e` should always be a Map<String, dynamic>
          return data.map((e) => fromJson(e as Map<String, dynamic>)).toList();
        } else {
          return [];
        }
      }
    

    Now there is no need to have BaseData and to extend it. Simply call _fromJsonList(jsonList, CommonOption.fromJson) on your list.