jsonEncode 不适用于枚举扩展;有解决方法吗?

Posted

技术标签:

【中文标题】jsonEncode 不适用于枚举扩展;有解决方法吗?【英文标题】:jsonEncode doesn't work with enum extensions; is there a workaround? 【发布时间】:2022-01-13 06:48:19 【问题描述】:

在 Dart (2.15.0) 中,我试图通过定义一个 toJson 方法来使用带有枚举的 jsonEncode。而且它不起作用。

import 'dart:convert';

enum Day  monday, tuesday 

extension ParseToJsonString on Day 
  String toJson() 
    return this.toString().split('.').last;
  


class Saturday 
  String toJson() => "WOOHOO Saturday";


main() 
  //works!
  Saturday s=Saturday();
  print(s.toJson());
  print(jsonEncode(s));
  
  Day m = Day.monday;
  print(m.toJson()); //prints 'monday'
  print(m); //prints Day.monday
  print(jsonEncode(m)); // Uncaught Error: Converting object to an encodable object failed: Instance of 'Day'

根据docs,jsonEncode会寻找toJson()方法。

当直接在枚举上调用时,扩展工作正常,但不知何故 jsonEncode 找不到 toJSON。

Dart How to get the "value" of an enum https://dart.dev/guides/language/extension-methods

知道这是错误还是预期的行为?

否则,我可以使用枚举并以某种方式定义与 jsonEncode 一起使用的东西吗?

谢谢!

【问题讨论】:

这是预期行为,因为扩展是“静态的”,并且在编译程序时静态解析,因此在运行时不是对象的一部分。这也意味着它只有在分析器可以确定特定类型时才有效(所以没有dynamic)。您链接到的文章有这样一段描述:“dynamic 不起作用的原因是扩展方法是针对接收器的静态类型解析的。因为扩展方法是静态解析的,所以它们的速度与调用静态函数。” 谢谢。经过一番挖掘,我终于弄明白了。可以通过重铸使其工作。 【参考方案1】:

我做了一些挖掘,由于 jsonEncode 的工作原理,这是正确的行为。

见https://github.com/dart-lang/sdk/issues/42742

注意,即使使用 jsonEncode 的可选参数也不能解决问题:

  print(jsonEncode(m, toEncodable: (x)=>x!.toJson()) ); // won't work.

要克服“扩展不适用于动态类型”,我们还必须使用重铸:

  print(jsonEncode(
    m,
    toEncodable: (x) 
      Day recastX = x as Day;
      return recastX.toJson();
    ,
  )); // works, prints 'monday'

查看dartpad

【讨论】:

以上是关于jsonEncode 不适用于枚举扩展;有解决方法吗?的主要内容,如果未能解决你的问题,请参考以下文章

ActionResult 扩展不适用于 Page() ActionResult 方法

在 Swift 中将 JSONEncoder 用于 Equatable 方法

React 建议和自动完成不适用于 VSCode 中带有 js 扩展名的文件

作为映射键的字符串枚举不适用于 ReturnType

Laravel 需要 Mcrypt PHP 扩展。不适用于 cron 作业

为啥 imagecreatefromjpeg 不适用于 .jpg 扩展名?