Dart 3中Freezed结合密封类与fromJson的正确使用方法咨询
如何用Dart 3密封类结合Freezed实现fromJson序列化?
Freezed文档提到应使用Dart 3原生密封类,但未说明如何结合fromJson方法实现序列化。下面针对这个问题给出解决方案:
原联合类型实现(正确适配Dart 3密封类的雏形)
你原来的写法其实已经符合Dart 3密封类的用法逻辑,只是需要明确Freezed对密封类的支持规则:
import 'package:freezed_annotation/freezed_annotation.dart'; part 'example.freezed.dart'; part 'example.g.dart'; @freezed sealed class Example with _$Example { const factory Example.text({ required String text, }) = _ExampleText; const factory Example.nameLocation({ required String name, required String location, }) = _ExampleNameLocation; factory Example.fromJson( Map<String, dynamic> json, ) => _$ExampleFromJson(json); } void main() { print(Example.fromJson({'runtimeType': 'text', 'text': 'Hello'})); print(Example.fromJson({ 'runtimeType': 'nameLocation', 'name': 'John', 'location': 'Amsterdam' })); }
你的错误写法及原因
你尝试将父类和子类分开标记@freezed,这种写法会导致Freezed生成的子类代码无法继承父类的序列化方法,从而报错:The non-abstract class '_$ExampleTextImpl' is missing implementations for these members: _$Example.toJson
错误代码:
import 'package:freezed_annotation/freezed_annotation.dart'; part 'example.freezed.dart'; part 'example.g.dart'; @freezed sealed class Example with _$Example { const factory Example() = _Example; factory Example.fromJson( Map<String, dynamic> json, ) => _$ExampleFromJson(json); } @freezed class ExampleText extends Example with _$ExampleText { const factory ExampleText({required String text}) = _ExampleText; } @freezed class ExampleNameLocation extends Example with _$ExampleNameLocation { const factory ExampleNameLocation({ required String name, required String location, }) = _ExampleNameLocation; } void main() { print(Example.fromJson({'runtimeType': 'ExampleText', 'text': 'Hello'})); print(Example.fromJson({ 'runtimeType': 'ExampleNameLocation', 'name': 'John', 'location': 'Amsterdam' })); }
正确的Dart 3密封类+Freezed序列化实现
核心规则:仅在根密封类上添加@freezed注解,所有变体通过根类的工厂构造函数定义,Freezed会自动处理所有子类的序列化逻辑。
标准实现
import 'package:freezed_annotation/freezed_annotation.dart'; part 'example.freezed.dart'; part 'example.g.dart'; // 仅根密封类标记@freezed,结合Dart 3 sealed关键字 @freezed sealed class Example with _$Example { // 定义各个业务变体的工厂构造函数 const factory Example.text({required String text}) = _ExampleText; const factory Example.nameLocation({ required String name, required String location, }) = _ExampleNameLocation; // 反序列化方法,Freezed自动生成所有变体的解析逻辑 factory Example.fromJson(Map<String, dynamic> json) => _$ExampleFromJson(json); } void main() { // 用法和原来完全一致,通过runtimeType指定变体类型 print(Example.fromJson({'runtimeType': 'text', 'text': 'Hello'})); print(Example.fromJson({ 'runtimeType': 'nameLocation', 'name': 'John', 'location': 'Amsterdam' })); }
如需显式定义子类扩展方法
如果需要给特定变体添加自定义方法,可以显式定义子类,但依然要在根密封类的工厂构造函数中关联:
@freezed sealed class Example with _$Example { const factory Example.text({required String text}) = _ExampleText; const factory Example.nameLocation({ required String name, required String location, }) = _ExampleNameLocation; factory Example.fromJson(Map<String, dynamic> json) => _$ExampleFromJson(json); } // 显式定义子类,用于添加自定义方法 class _ExampleText extends Example { const _ExampleText({required super.text}); // 自定义业务方法 void logText() => print('当前文本:$text'); }
关键注意点
- Dart 3的
sealed关键字和Freezed结合时,不需要拆分父类、子类单独标注@freezed,否则会导致代码生成冲突 - Freezed会自动为所有生成的密封类变体实现
toJson/fromJson所需的方法,无需手动实现 - 反序列化时依然依赖
runtimeType字段识别具体变体,字段值对应根类工厂构造函数的名称(比如text、nameLocation)
内容的提问来源于stack exchange,提问作者Roboroads
相关产品推荐
相关产品推荐

