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

Dart Floor如何正确实现TypeConverter的多层继承层级

问题场景

我如下定义了ListConverter<T>以搭建类型转换器的继承层级:

abstract class ListConverter<T> extends TypeConverter<List<T>, String> {
  static const delimiter = "!DELIMITER!";

  T fromDB(String databaseValue);

  String toDB(T value);

  @override
  List<T> decode(String databaseValue) {
    return databaseValue
        .split(delimiter)
        .where((element) => element.isNotEmpty)
        .map((e) => fromDB(e))
        .toList();
  }

  @override
  String encode(List<T> value) {
    return value.map((e) => toDB(e)).join(delimiter);
  }
}

基于ListConverter<T>,我实现了IntListConverter:

class IntListConverter extends ListConverter<int> {
  @override
  int fromDB(String databaseValue) {
    return int.parse(databaseValue);
  }

  @override
  String toDB(int value) {
    return value.toString();
  }
}

原本计划复用ListConverter<T>实现StringListConverter等其他列表转换器,但运行floor_generator时出现如下报错:

[SEVERE] floor_generator:floor_generator on lib/persistence/db/app_database.dart:
Only classes that inherit from TypeConverter can be used as type converters. Make sure use a class that inherits from TypeConverter.

已知直接继承TypeConverter的(B)层级可正常运行,但希望搭建(A)所示的三层继承结构以统一管理各类列表转换器:

  • (A) TypeConverter -> ListConverter -> IntListConverter
  • (B) TypeConverter -> IntListConverter

如何在Dart Floor中正确构建TypeConverter的继承层级?

解决方案

报错核心原因是floor_generator的类型转换器校验逻辑默认仅检查类的直接父类是否为TypeConverter,不会递归遍历多层继承链,因此中间隔了泛型抽象类ListConverter<T>时,生成器无法识别子类的转换器身份。可通过以下两种方案实现三层复用结构:

方案1:给中间基类添加@TypeConverter注解(Floor 1.2.0及以上版本支持)

直接在抽象基类ListConverter<T>上添加@TypeConverter()注解,标记该类为类型转换器基类,生成器就会顺着继承链识别所有子类的转换器身份,原有代码逻辑不需要做其他改动:

@TypeConverter() // 仅需添加这一行注解
abstract class ListConverter<T> extends TypeConverter<List<T>, String> {
  static const delimiter = "!DELIMITER!";

  T fromDB(String databaseValue);

  String toDB(T value);

  @override
  List<T> decode(String databaseValue) {
    return databaseValue
        .split(delimiter)
        .where((element) => element.isNotEmpty)
        .map((e) => fromDB(e))
        .toList();
  }

  @override
  String encode(List<T> value) {
    return value.map((e) => toDB(e)).join(delimiter);
  }
}

后续实现StringListConverter等其他列表转换器时,只需要继承ListConverter<T>并实现对应泛型的fromDB、toDB方法即可,不需要额外添加注解。

方案2:使用Mixin抽离通用逻辑(兼容所有Floor版本)

如果使用的Floor版本较低不支持基类注解,可以把列表编解码的通用逻辑抽离为Mixin,让具体转换器类直接继承TypeConverter的同时混入通用逻辑,既满足生成器对直接父类的校验要求,又不需要重复编写列表编解码代码:

// 抽离通用列表转换逻辑为Mixin
mixin ListConverterMixin<T> on TypeConverter<List<T>, String> {
  static const delimiter = "!DELIMITER!";

  T fromDB(String databaseValue);
  String toDB(T value);

  @override
  List<T> decode(String databaseValue) {
    return databaseValue
        .split(delimiter)
        .where((element) => element.isNotEmpty)
        .map((e) => fromDB(e))
        .toList();
  }

  @override
  String encode(List<T> value) {
    return value.map((e) => toDB(e)).join(delimiter);
  }
}

// int列表转换器:直接继承TypeConverter,混入通用逻辑
class IntListConverter extends TypeConverter<List<int>, String> with ListConverterMixin<int> {
  @override
  int fromDB(String databaseValue) {
    return int.parse(databaseValue);
  }

  @override
  String toDB(int value) {
    return value.toString();
  }
}

// String列表转换器示例
class StringListConverter extends TypeConverter<List<String>, String> with ListConverterMixin<String> {
  @override
  String fromDB(String databaseValue) => databaseValue;

  @override
  String toDB(String value) => value;
}

优先选择方案1,代码结构和初始设计完全一致,改动量最小。


内容的提问来源于stack exchange,提问作者Jaewoo Pyo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 11:15:29