flutter: 类型 '_InternalLinkedHashMap<Object?, Object?>' 不是类型 'Map<String, dynamic>' 的子类型

flutter: type '_InternalLinkedHashMap<Object?, Object?>' is not a subtype of type 'Map<String, dynamic>'

我在序列化我的 json 时遇到此错误。 我不确定我是否理解错误,但我发现如果我尝试在那里打印一些东西,代码永远不会到达 Prices.fromJson。如您所见,我正在使用 Firebase Cloud Functions return 具有嵌套数据对象的数据,但我很难将它们序列化。

代码:

class Price {
  final DateTime validFrom;
  final DateTime validTo;
  final double nokPerKwh;

  const Price({
    required this.validFrom,
    required this.validTo,
    required this.nokPerKwh,
  });

  factory Price.fromJson(Map<String, dynamic> json) {
    return Price(
      validFrom: DateTime.parse(json['validFrom']),
      validTo: DateTime.parse(json['validTo']),
      nokPerKwh: json['nokPerKwh'],
    );
  }
}

class Prices {
  final double now;
  final Price lowest;
  final Price highest;

  const Prices({
    required this.now,
    required this.lowest,
    required this.highest,
  });

  factory Prices.fromJson(Map<String, dynamic> json) {
    return Prices(
      now: json['now'],
      lowest: Price.fromJson(json['lowest']),
      highest: Price.fromJson(json['highest']),
    );
  }
}

class ShowerCost {
  final DateTime time;
  final int minutes;
  final Prices prices;

  const ShowerCost({
    required this.time,
    required this.minutes,
    required this.prices,
  });

  factory ShowerCost.fromJson(Map<String, dynamic> json) {
    print(json); <--- {minutes: 20, time: 2022-02-07T23:46:41.625Z, prices: {now: 11.848, highest: null, lowest: {nokPerKwh: 1.1848, validFrom: 2022-02-08T00:00:00+01:00, validTo: 2022-02-08T01:00:00+01:00}}}
    return ShowerCost(
      time: DateTime.parse(json['time']),
      minutes: json['minutes'],
      prices: Prices.fromJson(json['prices']),
    );
  }
}

Future<ShowerCost> getShowerCost() async {
  try {
    HttpsCallable callable =
        FirebaseFunctions.instance.httpsCallable('getShowerCost');
    final results = await callable.call(<String, dynamic>{
      'minutes': 20,
      'time': DateTime.now().toIso8601String(),
      'minHour': DateTime(2022, 2, 7, 0).toIso8601String(),
      'maxHour': DateTime(2022, 2, 7, 23).toIso8601String()
    });
    return ShowerCost.fromJson(results.data);
  } catch (error) {
    print(error);
    return Future.error(error);
  }
}

使用这个:

final myMap = Map<String, dynamic>.from(results.data);
return Prices.fromJson(myMap);

您可以使用 dart:convert 包中的 json.decode

    final results = await callable.call(<String, dynamic>{
      'minutes': 20,
      'time': DateTime.now().toIso8601String(),
      'minHour': DateTime(2022, 2, 7, 0).toIso8601String(),
      'maxHour': DateTime(2022, 2, 7, 23).toIso8601String()
    });
    // Try
    final data = Map<String, dynamic>.from(results.data) as Map<String, dynamic>
    // or
    final data = results.data.toMap()

    return ShowerCost.fromJson(data);

@rapaterno 和@mohamed abu-ghazalla 的回答都为我指明了正确的方向。 使用 Map<String, dynamic>.from(...) 转换为 Map<String, dynamic> 需要在所有 child 的 fromJson() 参数中发生:

factory Price.fromJson(Map<String, dynamic> json) {
  return Price(
    validFrom: DateTime.parse(json['validFrom']),
    validTo: DateTime.parse(json['validTo']),
    nokPerKwh: json['nokPerKwh'],
  );
}

factory Prices.fromJson(Map<String, dynamic> json) {
  return Prices(
    now: json['now'],
    lowest: Price.fromJson(Map<String, dynamic>.from(json['lowest'])),   <--- HERE
    highest: Price.fromJson(Map<String, dynamic>.from(json['highest'])), <--- HERE
  );
}

factory ShowerCost.fromJson(Map<String, dynamic> json) {
  return ShowerCost(
    time: DateTime.parse(json['time']),
    minutes: json['minutes'],
    prices: Prices.fromJson(Map<String, dynamic>.from(json['prices'])),  <--- HERE
  );
}

Future<ShowerCost> getShowerCost() async {
  try {
    HttpsCallable callable =
        FirebaseFunctions.instance.httpsCallable('getShowerCost');
    final results = await callable.call(<String, dynamic>{
      'minutes': 20,
      'time': DateTime.now().toIso8601String(),
      'minHour': DateTime(2022, 2, 8, 0).toIso8601String(),
      'maxHour': DateTime(2022, 2, 8, 23).toIso8601String()
    });
    return ShowerCost.fromJson(results.data);
  } catch (error) {
    print(error);
    return Future.error(error);
  }
}