英文:
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;
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论