4

如何使Freezed对象采用泛型类型?我想做这个:

import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:vepo/src/entity_types/option_entity.dart';

part 'vegan_item_tag.freezed.dart';
part 'vegan_item_tag.g.dart';

@freezed
abstract class VeganItemTag<T>
    with _$VeganItemTag<T>
    implements OptionEntity<T> {
  const factory VeganItemTag({int? iconCodePoint, T? id, String? name}) =
      _VeganItemTag;

  const VeganItemTag._();

  factory VeganItemTag.fromJson(Map<String, dynamic> json) =>
      _$VeganItemTagFromJson(json);
}

我已经尝试@With.fromString('AdministrativeArea<House>')从文档中使用,但无法将其正确应用于此类。

错误之一:

lib/src/common/enums/tags/common/vegan_item_tag.freezed.dart:142:32:错误:位置参数太少:需要 2 个,给定 1 个。
$ $_VeganItemTagFromJson(json);

认为我可能在正确的轨道上,但它不再生成vegan_item_tag.g.dart文件:

@freezed
abstract class VeganItemTag<T>
    with _$VeganItemTag<T>
    implements OptionEntity<T> {
  const factory VeganItemTag(
      {required int iconCodePoint,
      required T id,
      required String name}) = _VeganItemTag;

  const VeganItemTag._();

  factory VeganItemTag.fromJson(
    Map<String, Object?> json,
    T Function(Object?) fromJsonT,
  ) => VeganItemTag(
      iconCodePoint: json['iconCodePoint'] as int,
      id: fromJsonT(json['id']),
      name: json['name'] as String,
    );
}
4

2 回答 2

5

这个问题有几种解决方案。但在所有这些中,您需要将您的类显式转换为 Firebase 可以处理的泛型类型,例如StringMap<dynamic, String>

实现这种行为的 3 种方法是:

FromJson ToJson

这比JsonConverters复杂场景更难维护,所以我会为您的解决方案放弃这个选项。

json转换器

它适用于通过继承自动转换特定类或抽象类,但是从具有不同数据的泛型类型来存储它可能不是您需要的。如果您总是从泛型类型中保存相同的值,T您可以尝试通过实现的抽象类来使用此解决方案。

GenericArgumentFactory

这就是你真正要问的。在json_serializable和Freezed使用 genericArgumentFactories并不容易,同时我在Freezed 包上发现了一个错误。

但我设法让这段代码工作,这是实际的解决方案。

@freezed
@JsonSerializable(genericArgumentFactories: true)
class VeganItemTagV2<T> with _$VeganItemTagV2<T> {
  const VeganItemTagV2._();

  const factory VeganItemTagV2({
    required int iconCodePoint,
    required T id,
    required String name,
  }) = _VeganItemTag<T>;

  //It only works with block bodies and not with expression bodies
  //I don't know why
  factory VeganItemTagV2.fromJson(
      Map<String, dynamic> json, T Function(Object? json) fromJsonT) {
    return _$VeganItemTagV2FromJson<T>(json, fromJsonT);
  }

  Map<String, dynamic> toJson(Object Function(T value) toJsonT) {
    return _$VeganItemTagV2ToJson<T>(this, toJsonT);
  }
}

这会根据泛型类型添加要使用的toJson和方法上的转换器。fromJson

笔记。这些方法不能作为某些错误的表达式,因为它不能编译,但它适用于块体。Freezed 不正式支持它,因此您可以考虑在没有 Freezed 包的情况下创建此类。

这是一个封装了 aString类和一个测试类的例子,看看它是如何工作的:

class VeganId {
  final String id;

  VeganId(this.id);

  String itemId() {
    return id;
  }

  @override
  String toString() {
    return 'VeganId{id: $id}';
  }

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is VeganId && runtimeType == other.runtimeType && id == other.id;

  @override
  int get hashCode => id.hashCode;
}

以及运行良好的测试

  test('veganItemV2 from and toJson', () {
    final dto = VeganItemTagV2<VeganId>(
      iconCodePoint: 1,
      id: VeganId("veganID"),
      name: "name",
    );

    final Map<String, dynamic> actualToJson = dto.toJson((id) => id.itemId());

    expect(actualToJson, {"iconCodePoint": 1, "id": "veganID", "name": "name"});

    final VeganItemTagV2 actualFromJson = VeganItemTagV2<VeganId>.fromJson(
      actualToJson,
      (json) =>
        VeganId(json as String),
    );

    expect(actualFromJson, dto);
  });
于 2021-06-14T13:41:56.613 回答
0

您的最后一个代码不会生成,因为您在工厂vegan_item_tag.g.dart编写了错误的代码。VeganItemTag.fromJson编辑它是这样的:

factory VeganItemTag.fromJson(
    Map<String, Object?> json,
    T Function(Object?) fromJsonT,
  ) => _$VeganItemTagFromJson(json, fromJsonT);

或者:

factory VeganItemTag.fromJson(Map<String, Object?> json) =>
    _$VeganItemTagFromJson(json);

然后重新运行flutter pub run build_runner build --delete-conflicting-outputs命令。

于 2021-06-10T05:35:56.627 回答