【问题标题】:How can we get object index based on object property from a generic function? | Dart我们如何从泛型函数中获取基于对象属性的对象索引? |镖
【发布时间】:2022-07-21 21:19:48
【问题描述】:

我为我的数据库 crud 操作设置了一组很好的通用函数。对于一些专门的功能,我需要更细粒度的控制。我希望能够按属性搜索数据库对象列表。似乎不可能,有一个警告 - 所有对象都将具有 uuid 的属性,这是我想要搜索的。太好了……用 SO 的一些天才头脑一定是可能的。

当然,我想做这样的事情:

Future<int> getExampleIndexByUUID({required String uuid}) async 
  => await Hive.openBox<Example>('Example_Box')
     .then((box) => box.values.toList().indexWhere(example)
       => example.uuid == uuid);

但以上对于泛型类型是不可能的:

Future<T> getExampleIndexByUUID<T>({
  required T objectType,
  required String uuid,
  }) async => await Hive.openBox<T>(objectDatabaseNameGetter(objectType))
  .then((box) => box.values.toList().indexWhere(example)
    => example... );                    // Dead end- no property access here

PS 我知道我可以在通用函数之外创建方法来处理这个问题。我还可以创建另一个大型开关盒来处理这个问题,但这是我想要避免的。我想学习在这种情况下更好地抽象我的代码。任何帮助或指针表示赞赏!如果我唯一的选择是拥有一个开关盒或在功能之外进行工作,那就这样吧。

【问题讨论】:

  • 我不确定我是否理解你的问题(你没有解释为什么它不可能或为什么代码是“死胡同”),但如果你的意思是你想访问不同的基于泛型类型的属性,将回调传递给泛型函数以访问所需的属性。
  • 是的,这正是我的意思,因为泛型类型我没有属性访问权限(在我所说的“死代码”的地方)。我将更新我的问题以更具体。我将如何构建该回调?我不知道该怎么做?

标签: flutter dart generics abstraction


【解决方案1】:
  • 定义一个通用接口。

    最好的方法是让所有具有uuid 属性的类共享一个公共基类,然后您的泛型函数可以将其类型参数限制为该类的子类型:

    abstract class HasUuid {
      String get uuid;
    }
    
    class Example implements HasUuid {
      @override
      String uuid;
    
      Example(this.uuid);
    }
    
    Future<int> getExampleIndexByUUID<T extends HasUuid>({
      required T objectType,
      required String uuid,
    }) async {
      var box = await Hive.openBox<T>(objectDatabaseNameGetter(objectType));
      return box.values.toList().indexWhere(
        (example) => example.uuid == uuid),
      );
    }
    
  • 使用回调。

    如果您不控制要使用的类,则可以让泛型函数接受回调来检索所需的属性。这对调用者来说工作量更大,但也更灵活,因为调用者可以选择访问哪个属性。

    Future<int> getExampleIndexByUUID<T>({
      required T objectType,
      required String Function(T) getUuid,
      required String uuid,
    }) async {
      var box = await Hive.openBox<T>(objectDatabaseNameGetter(objectType));
      return box.values.toList().indexWhere(
        (example) => getUuid(example) == uuid),
      );
    }
    

    你可以进一步概括:

    Future<int> getExampleIndex<T, PropertyType>({
      required T objectType,
      required PropertyType Function(T) getProperty,
      required PropertyType propertyValue,
    }) async {
      var box = await Hive.openBox<T>(objectDatabaseNameGetter(objectType));
      return box.values.toList().indexWhere(
        (example) => getProperty(example) == propertyValue),
      );
    }
    
  • 使用鸭式打字。

    如果您可以保证所有提供的类型都有uuid 成员,另一种选择是使用dynamic 和duck-typing(放弃静态类型安全):

    Future<int> getExampleIndexByUUID<T>({
      required T objectType,
      required String Function(T) getUuid,
      required String uuid,
    }) async {
      var box = await Hive.openBox<T>(objectDatabaseNameGetter(objectType));
      return box.values.toList().indexWhere(
        (dynamic example) => example.uuid == uuid),
      );
    }
    

顺便说一句,将async/awaitFuture.then 混合使用是一种不好的风格。只需使用async/await

【讨论】:

  • 美丽而翔实的答案。我喜欢第一个,尤其是对于未来的项目,但是在我现在的位置上,控制我的对象类太过分了。我将使用回调选项。至于我的混合 async/await 和 Future.then 的风格,请指出。但是,我不得不承认,有时我的代码很古怪,我喜欢“内联”更短的函数来吸引自己的眼球。当然,您可以说我不在团队中工作;p无论如何,感谢您提供详细而有启发性的答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2021-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-25
  • 2018-04-13
相关资源
最近更新 更多