英文:
How can I create a generic implementation of fromJson and toJson in Dart?
问题
我正在尝试实现一种允许使用泛型类型创建扩展类实例的继承模式。下面的代码似乎是一种有效的模式,但编译器抱怨说 T.fromJson() 未实现。具体而言,在VS Code中,它显示以下错误,带有红色下划线波浪线:
“方法 'fromJson' 未定义于类型 'Type'。请尝试更正名称为现有方法的名称,或定义名为 'fromJson' 的方法。”
我在重构过程中遇到了这个问题,但成功创建了一个我认为应该工作的半简化示例:
class TestClass {
TestClass();
factory TestClass.fromJson(Map<String, dynamic> json) => TestClass();
}
class ATest extends TestClass {
ATest();
@override
factory ATest.fromJson(Map<String, dynamic> json) => ATest();
}
class BTest extends TestClass {
BTest();
@override
factory BTest.fromJson(Map<String, dynamic> json) => BTest();
}
class CTest extends TestClass {
CTest();
@override
factory CTest.fromJson(Map<String, dynamic> json) => CTest();
}
class FactoryController<T extends TestClass> {
Future<List<T>> listNetworkObjects<T extends TestClass>({
required List<String> filters,
}) async {
try {
final data = await MockApi().mockApiCall<T>(filters);
final List<T> allItems = List<T>.from(
data.map((T model) => T.fromJson(model)),
);
if (allItems.isNotEmpty) {
print('Received Items from the API.');
}
return allItems;
} catch (getTestClassError, stackTrace) {
print('Error getting TestClasses');
print(stackTrace);
return <T>[];
}
}
}
class MockApi {
MockApi();
dynamic mockApiCall<T extends TestClass>(List<String> filters) async {
final dynamic data = {"test": "object"};
return data;
}
}
我期望方法 listNetworkObjects<T extends TestClass>
将为编译器提供基类以及所有实现它的类提供的 .fromJson()
方法的可见性。
与 data.map((T model) => T.fromJson(model))
不同,我尝试了以下选项:
data.map((T model) => T().fromJson(model))
data.map((T model) => new T.fromJson(model))
data.map((T model) => new T().fromJson(model))
data.map((model as T) => T.fromJson(model))
data.map((T model) => T.new.fromJson(model))
每种方式都失败了,但有不同的失败原因。
我看到了其他类似的问题,例如有关抽象类构造函数的问题,但我的基类并不是抽象的。我还尝试使用 implements
而不是 extends
,但:
listNetworkObjects<T implements TestClass>()
不是有效的方法或类规范。我觉得答案可能在这里,但我无法弄清楚如何正确实现它:
https://stackoverflow.com/questions/23112130/creating-an-instance-of-a-generic-type-in-dart。
谢谢!
英文:
I am attempting to implement an inheritance pattern that allows for creating instances of an extended class using generic types. The below code appears to be a working pattern, yet the compiler complains that T.fromJson() is not implemented. Specifically, it gets red underlined squiggles in VS Code with the following error:
The method 'fromJson' isn't defined for the type 'Type'. Try correcting the name to the name of an existing method, or defining a method named 'fromJson'.
I am encountering this during a refactor effort but was able to create a semi-simplified example of the pattern I think should work:
class TestClass{
TestClass();
factory TestClass.fromJson( Map<String, dynamic> json ) => TestClass();
}
class ATest extends TestClass {
ATest();
@override
factory ATest.fromJson( Map<String, dynamic> json ) => ATest();
}
class BTest extends TestClass {
BTest();
@override
factory BTest.fromJson( Map<String, dynamic> json ) => BTest();
}
class CTest extends TestClass {
CTest();
@override
factory CTest.fromJson( Map<String, dynamic> json ) => CTest();
}
class FactoryController<T extends TestClass>{
Future<List<T>> listNetworkObjects<T extends TestClass>({
required List<String> filters,
}) async {
try {
final data = await MockApi().mockApiCall<T>( filters );
final List<T> allItems = List<T>.from(
data.map( ( T model ) => T.fromJson( model ) )
);
if ( allItems.isNotEmpty ) {
print( 'Received Items from the API.' );
}
return allItems;
}
catch ( getTestClassError, stackTrace ) {
print( 'Error getting TestClasses' );
print( stackTrace );
return <T>[];
}
}
}
class MockApi{
MockApi();
dynamic mockApiCall<T extends TestClass>(
List<String> filters
) async {
final dynamic data = { "test": "object" };
return data;
}
}
I would expect that the method listNetworkObjects<T extends TestClass> would provide visibility to the compiler that the base class and all implementations of it also provide an implementation of the .fromJson() method of the class.
Instead of data.map( ( T model ) => T.fromJson( model ) )
I have tried:
data.map( ( T model ) => T().fromJson( model ) )
data.map( ( T model ) => new T.fromJson( model ) )
data.map( ( T model ) => new T().fromJson( model ) )
data.map( ( model as T ) => T.fromJson( model ) )
data.map( ( T model ) => T.new.fromJson( model ) )
each of which fails for a different reason.
I see other similar questions about abstract class constructors etc. like
https://stackoverflow.com/questions/69943865/flutter-abstract-class-with-factory-methods
but my base class is not abstract. I also tried with using implements
instead of extends
but:
listNetworkObjects<T implements TestClass>()
is not a valid method or class specification. I feel like there could be an answer here but I can't figure out how to implement it properly:
https://stackoverflow.com/questions/23112130/creating-an-instance-of-a-generic-type-in-dart.
Thanks!
答案1
得分: 0
Dart存在一个限制,不能调用泛型类型的静态方法(包括构造函数和工厂方法)。
在某些情况下,我曾经使用以下类似的模式,缺点是它需要传入一个实例化的该类型对象:
abstract class TestClass {
TestClass fromJson(Map<String, dynamic> json);
}
class Foo<T extends TestClass> {
T someMethod(T proto) => proto.fromJson(...) as T;
}
英文:
It is a limitation of Dart that static methods of generic types cannot be called (including constructors and factories).
In some situations I've used a pattern like below, with the disadvantage that it requires an instantiated object of the type to be passed in:
abstract class TestClass{
TestClass fromJson(Map<String, dynamic> json);
}
class Foo<T extends TestClass> {
T someMethod(T proto) => proto.fromJson(...) as T;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论