我们如何从泛型函数中获取基于对象 属性 的对象索引? |镖
How can we get object index based on object property from a generic function? | Dart
我已经为我的数据库 crud 操作设置了一组很好的通用函数。我需要对一些专门功能进行更细粒度的控制。我希望能够按 属性 搜索数据库对象列表。似乎不可能,有一个警告 - 所有对象都将具有 属性 的 uuid,这是我想要搜索的。 Sooo... 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 我知道我可以在通用函数之外创建方法来处理这个问题。我还可以创建另一个大型 switch case 来处理这个问题,但这是我想要避免的。我想学习在这种情况下更好地抽象我的代码。任何帮助或指点表示赞赏!如果我唯一的选择是有一个开关盒或在函数之外做工作,那就这样吧。
定义一个公共接口。
最好的方法是让所有具有 uuid
属性 的 classes 共享一个公共基础 class,然后您的通用函数可以将其类型参数限制为 class:
的子类型
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),
);
}
使用回调。
如果您不控制要使用的 classes,您可以让通用函数接受回调而不是检索所需的 属性。这对呼叫者来说会更麻烦,但它也会更灵活,因为呼叫者可以选择 属性 访问哪个。
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),
);
}
使用duck-typing.
如果您可以保证所有提供的类型都有一个 uuid
成员,另一种选择是使用 dynamic
和 duck-typing(放弃静态 type-safety):
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
/await
与 Future.then
混合使用是一种糟糕的风格。只需使用 async
/await
.
我已经为我的数据库 crud 操作设置了一组很好的通用函数。我需要对一些专门功能进行更细粒度的控制。我希望能够按 属性 搜索数据库对象列表。似乎不可能,有一个警告 - 所有对象都将具有 属性 的 uuid,这是我想要搜索的。 Sooo... 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 我知道我可以在通用函数之外创建方法来处理这个问题。我还可以创建另一个大型 switch case 来处理这个问题,但这是我想要避免的。我想学习在这种情况下更好地抽象我的代码。任何帮助或指点表示赞赏!如果我唯一的选择是有一个开关盒或在函数之外做工作,那就这样吧。
定义一个公共接口。
最好的方法是让所有具有
的子类型uuid
属性 的 classes 共享一个公共基础 class,然后您的通用函数可以将其类型参数限制为 class: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), ); }
使用回调。
如果您不控制要使用的 classes,您可以让通用函数接受回调而不是检索所需的 属性。这对呼叫者来说会更麻烦,但它也会更灵活,因为呼叫者可以选择 属性 访问哪个。
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), ); }
使用duck-typing.
如果您可以保证所有提供的类型都有一个
uuid
成员,另一种选择是使用dynamic
和 duck-typing(放弃静态 type-safety):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
/await
与 Future.then
混合使用是一种糟糕的风格。只需使用 async
/await
.