【问题标题】:Validating freezed model classes验证冻结模型类
【发布时间】:2021-04-05 11:58:46
【问题描述】:

我正在寻找一种验证freezed 模型的好方法。到目前为止,我想出了三种方法,如下面的 sn-p 所示。

@freezed
class Options with _$Options {
  Options._();

  factory Options._internal({required List<String> languages}) = _Options;

  // #1: validation in factory constructor
  factory Options({required List<String> languages}) {
    if (languages.isEmpty) {
      throw Exception('There must be at least one language.');
    }

    return Options._internal(languages: languages);
  }

  // #2: expose mutation methods with built-in validation
  Options changeLanguages(List<String> languages) {
    if (languages.isEmpty) {
      throw Exception('There must be at least one language.');
    }
    return copyWith(languages: languages);
  }

  // #3: validation using custom properties
  late final List<Exception> validationResult = <Exception>[
    if (languages.isEmpty) Exception('There must be at least one language.'),
  ];

  // #4: validation using a custom method
  void validate() {
    if (languages.isEmpty) {
      throw Exception('There must be at least one language.');
    }
  }
}

#1: 在工厂构造函数中进行验证。不幸的是,这仅适用于新创建的对象,需要对 copyWith 进行进一步更改。

#2: 变异方法内的验证。除了 #1 之外,这还可用于在对象创建后运行验证,但仍不适用于 copyWith

#3: 暴露带有验证错误的属性。到目前为止,这是我最喜欢的方法,尽管它要求模型的用户明确查找错误。

#4:#3 的变体,它使用抛出方法而不是提供错误列表。

您对此有何看法?您是否知道任何更好的 方法,或者是否有我忽略的包 API 的一部分?

【问题讨论】:

    标签: flutter validation dart freezed


    【解决方案1】:

    v0.12.0:https://pub.dev/packages/freezed#asserts 中添加了对自定义asserts 的支持。将这些应用于您的示例会产生以下结果:

    @freezed
    abstract class Options with _$Options {
      Options._();
    
      @Assert('languages.isNotEmpty', 'There must be at least one language.')
      factory Options({required List<String> languages}) = _Options;
    }
    

    但是,这不允许您抛出任意异常,并且asserts 仅包含在调试版本中,而不包含在配置文件/发布版本中。

    【讨论】:

    • 断言非常适合仅用于调试目的,但我正在寻找一种解决方案,它允许抛出面向用户的异常。不过谢谢!
    【解决方案2】:

    我可能会将验证移到下一级。可以创建模型LanguageList

    class LanguageList {
      LanguageList(this.data) {
        if (data.isEmpty) throw ArgumentError('Provide at least one element');
      }
      
      final List<String> data;
    
      @override
      bool operator ==(Object other) => other is LanguageList && ListEquality<String>.equals(data, other.data);
    
      @override
      int get hashCode => DeepCollectionEquality().hash(data);
    }
    

    并在Options 模型中使用它:

    factory Options._internal({required LanguageList languages}) = _Options;
    

    您甚至可以通过使非法状态无法表示而不是在运行时引发错误来使其更加“编译友好”:

    class LanguageList {
      LanguageList(String head, Iterable<String> tail) : data = [head, ...tail];
      
      final List<String> data;
    
      @override
      bool operator ==(Object other) => other is LanguageList && ListEquality<String>.equals(data, other.data);
    
      @override
      int get hashCode => DeepCollectionEquality().hash(data);
    }
    

    在这种情况下,没有办法创建错误的实例。

    【讨论】:

    • 虽然我喜欢这个解决方案,但我正在寻找一种方法来准确表达用 freezed 包构建的数据类的这种行为。据我所知,目前没有办法实现这一目标
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-07
    • 1970-01-01
    • 2022-07-20
    • 1970-01-01
    相关资源
    最近更新 更多