You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 19:53:17