在Dart中切换类类型

59

我想在Dart超类中编写一个函数,根据实际使用它的子类采取不同的操作。类似于这样:

class Foo {
  Foo getAnother(Foo foo) {
    var fooType = //some code here to extract fooType from foo;
    switch (fooType) {
      case //something about bar here:
        return new Bar();
      case //something about baz here:
        return new Baz();
    }
  }
}

class Bar extends Foo {}

class Baz extends Foo {}

我想要的是有一个对象,然后得到一个相同子类的新对象。

主要问题是fooType应该是什么类型?我的第一个想法是使用Symbol,这样就可以像case #Bar:一样轻松地进行分支语句,但我不知道如何用Symbol填充fooType。我能想到的唯一选项是做像Symbol fooType = new Symbol(foo.runtimeType.toString());这样的事情,但我了解到当转换成javascript时runtimeType.toString()无法工作。你可以通过使用Mirrors来解决这个问题,但这是一个轻量级库,所以这些方法不可行。Object.runtimeType返回Type类的某些内容,但我不知道如何创建Type类的实例,以便用于case语句。也许我忽略了某个更适合这种情况的Dart库?


子类的特殊行为取决于父类:这听起来正是虚函数旨在解决的问题。我们可以这样做:class Foo { Foo _createNew() => new Foo(); Foo getAnother(Foo foo) => foo._createNew(); } 然后 class Bar extends Foo { _createNew() => new Bar(); },对于 Baz 也是如此。 - lrn
2个回答

98
您可以在 switch 中使用 runtimeType
class Foo {
  Foo getAnother(Foo foo) {
    switch (foo.runtimeType) {
      case Bar:
        return new Bar();
      case Baz:
        return new Baz();
    }
    return null;
  }
}

case语句中直接使用类名(也称为类字面量)。这将给出与所提到类相对应的Type对象。因此,foo.runtimeType可以与指定类型进行比较。
请注意,在类字面量您现在无法使用泛型。因此,case List<int>:是不允许的。

3
这不能与ListMapSet和可能的其他类型一起使用。 - Günter Zöchbauer
我相信这个带有runtimeType的switch case语句会在pub build时出错(-> 'case'表达式类型'TypeImpl'覆盖了'operator ==')。将代码更改为字符串比较(foo.runtimeType.toString()case 'Bar')可以通过pub build - Naoto Hc
1
这会对性能产生任何影响吗?还是通常使用是安全的? - Linxy
1
@AlexandreArdhuin 这对我不起作用。以下示例打印“无匹配项。B”。https://dartpad.dartlang.org/2012b9264ee9ec79e8c9800d42d3fbef - ThinkDigital
请注意,dart analyze 不会对这种类型的 switch 语句进行详尽检查。为此,您需要使用枚举。 - mndrix
显示剩余6条评论

8
使用Flutter 3.0,你可以做到以下几点:
1. 定义类:
abstract class LoginActionsEvent {}
 
class LoginActionsCheckConnectionEvent implements LoginActionsEvent {
   const LoginActionsCheckConnectionEvent();
}

使用开关类型:
switch (event) {
  case final LoginActionsCheckConnectionEvent e:
    return _onLoginActionsCheckConnection(e, emit);
  default:
    throw UnimplementedError('Unknown event: $event');
}

2
这真是太方便了,谢谢你指出这一点。 - Koodimetsa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接