【问题标题】:How can I work around the new Dart changes which prohibit implementing the same interface with different generics?如何解决禁止使用不同泛型实现相同接口的新 Dart 更改?
【发布时间】:2018-04-12 19:07:21
【问题描述】:

出于必要,我的代码相当复杂。我试图简化我正在处理的对象系统的整体布局,以便(希望)使其更易于理解。

abstract class BaseType {}

abstract class MixinTypeA implements BaseType {}

abstract class MixinTypeB<T extends MixinTypeA> implements BaseType {
  Future<T> mixinMethod({bool argA = true,
      bool argB = true,
      bool argC = true}) =>
    someMethodCall()
}

abstract class BaseTypeA extends BaseType implements MixinTypeA {
  // declares a constructor
  BaseTypeA();
}

abstract class BaseTypeB extends BaseType implements MixinTypeB {
  // declares a constructor
  BaseTypeB();
}

abstract class TypeA extends BaseTypeA {}

class TypeB extends BaseTypeB with MixinTypeB<TypeA> {}

在这种情况下,TypeB 会产生错误。这是因为它试图混入MixinTypeB&lt;TypeA&gt;。因为 TypeB 已经扩展了BaseTypeB,它使用推断的&lt;MixinTypeA&gt; 泛型实现了MixinTypeB,所以MixinTypeB 接口使用两个不同的(尽管通过继承相关)接口实现了两次:TypeAMixinTypeA

本质上,T 泛型的存在是为了让我的代码保持干燥。 MixinTypeB 中的方法示例是该类可能具有的具有特定类型签名T 的各种潜在方法之一。我不知道如何在不损害这种类型系统的继承结构的情况下绕过新的限制。

【问题讨论】:

    标签: oop dart method-signature


    【解决方案1】:

    一般来说,最常见的解决方案是通过层次结构将泛型线程化以使类型对齐。对于此特定示例,以下代码有效。

    abstract class BaseType {}
    
    abstract class MixinTypeA implements BaseType {}
    
    abstract class MixinTypeB<T extends MixinTypeA> implements BaseType {
      Future<T> mixinMethod({bool argA = true,
          bool argB = true,
        bool argC = true}) => null;
    }
    
    abstract class BaseTypeA extends BaseType implements MixinTypeA {
      // declares a constructor
      BaseTypeA();
    }
    
    abstract class BaseTypeB<T extends MixinTypeA> extends BaseType implements MixinTypeB<T>{
      // declares a constructor
      BaseTypeB();
    }
    
    abstract class TypeA extends BaseTypeA {}
    
    class TypeB extends BaseTypeB<TypeA> with MixinTypeB<TypeA> {}
    

    如果您不需要将BaseTypeBMixinTypeB 的任何其他实例混合在一起,那么以下更简单的方法也可以工作:

    abstract class BaseType {}
    
    abstract class MixinTypeA implements BaseType {}
    
    abstract class MixinTypeB<T extends MixinTypeA> implements BaseType {
      Future<T> mixinMethod({bool argA = true,
          bool argB = true,
        bool argC = true}) => null;
    }
    
    abstract class BaseTypeA extends BaseType implements MixinTypeA {
      // declares a constructor
      BaseTypeA();
    }
    
    abstract class BaseTypeB extends BaseType implements MixinTypeB<TypeA>{
      // declares a constructor
      BaseTypeB();
    }
    
    abstract class TypeA extends BaseTypeA {}
    
    class TypeB extends BaseTypeB with MixinTypeB<TypeA> {}
    

    【讨论】:

    • 首先,感谢您的建议。您最初的假设是正确的——我需要能够将 BaseTypeB 用于多个类。然而,这个解决方案,“线程”,让我觉得有点奇怪。例如,对这个解决方案的一个警告是它会在 dartdocs 中奇怪地出现,具有对用户可见的无用的泛型。从逻辑上讲,该解决方案非常有意义。但在实践中,对我来说,这更像是一种变通方法,而不是一个适当的解决方案。但是,据我了解,这可能是唯一的解决方案。我很想听听你的想法!
    • 我认为我对您的原始代码没有足够的上下文来说明这是一种解决方法还是正确的做法。 :) 基于这个例子,我觉得很奇怪,你会让MixinTypeB 泛型而不是仅仅让mixinMethod 返回Future&lt;MixinTypeA&gt;,然后转身使用MixinTypeB 而没有泛型参数。我认为BaseTypeB 实现MixinTypeB 的唯一原因是您可以将其用作具有mixinMethod 的接口,对吗?但是为什么你不关心那个接口上有精确的泛型类型呢?
    • 在这种情况下使用泛型的目的主要是为了让mixinMethod 具有正确的类型签名。本质上,TypeATypeB 是相关联的。 TypeB 的继承 mixinMethod 应该返回 TypeA。此外,如果我要为 TypeA(因此也为 TypeB)创建一个子类,SubtypeB 必须让其mixinMethod 返回SubtypeA。我希望这是有道理的! :)
    • 是的,MixinTypeB 是通用的是有道理的,我不完全清楚的是为什么原始代码使 BaseTypeB 实现 MixinTypeB&lt;dynamic&gt; 而不是根本不实现它(因为无论如何您都将它混入TypeB),或者以特定类型实现它。不是说不合理,只是有点不明白。
    • 更一般地说,用不同的泛型参数实现相同的接口肯定有用途,这段代码完全有可能是其中之一。对于 Dart 2,我们认为这些用例非常罕见,值得在它们出现时对其进行处理,因为不支持它还有其他好处。有一个支持类型参数推断的提案,这可能会减少客户端代码中的样板:github.com/dart-lang/sdk/blob/master/docs/language/informal/…
    猜你喜欢
    • 1970-01-01
    • 2020-07-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 1970-01-01
    相关资源
    最近更新 更多