Dart类型转换错误

7

我有一个抽象类 Event,以及一个扩展它的具体子类 PlaceChangeEvent。在一个事件监听器中,我有以下代码:

void onEvent(Event event) {
    PlaceChangeEvent pce = null;
    if(event is PlaceChangeEvent)
        pce = (PlaceChangeEvent)event;      // <== error is here
    else
        throw new Exception("Event is not a PlaceChangeEvent.");

    Place place = pce.place;

    presenterProvider.display(place);
}

如果event的运行时类型是PlaceChangeEvent,那么我需要将事件强制转换为该类型,以便能够访问其属性。但是在类型转换中,我遇到了编译器错误,提示:

不能将类型为“Type”的值分配给类型为“PlaceChangeEvent”的变量

我错在哪里了,我需要做什么来修复它?

2个回答

8

在Dart中

  1. upcasts are implicit. If B is a subclass of A, then B b = a (where a is an instance of class A) is warning free and silently casts a to B. In Java you would have needed to write B b = (B) a.

  2. the dynamic type is an always-present escape hatch. If B and C are not in the same hierarchy, then temporarily assigning to the dynamic type will make the cast warning-free.

    B b = someB;
    var tmp = b;
    C c = tmp;
    
  3. One can do an explicit check using is. The is check returns true if the object is of the right type. There are also some very simple rules that propagate is-check types. For example, if is is used inside an if condition, then the corresponding branch uses this information for type-warnings.

    Object o;
    o.foo();  // warning: foo does not exist on Object.
    if (o is A) {  // assuming that A contains 'foo'.
      o.foo();  // warning-free.
    }
    
  4. One can explicitly check and throw if a type is not the expected one with as. This operator does not throw when the left-hand side is null.

对于你的例子,这归结为:

没有明确的检查(1):

void onEvent(Event event) {
  // Implicit upcast. PlaceChangeEvent is subclass of Event.
  PlaceChangeEvent pce = event;
  Place place = pce.place;
  presenterProvider.display(place);
}

使用 is-check(3):

void onEvent(Event event) {
  if (event is PlaceChangeEvent) {
    // Static type system propagates type. No need for variable.
    Place place = event.place;
    presenterProvider.display(place);
  } else {
    // Note: this doesn't look like an exception, but an error.
    throw new Exception("Event is not a PlaceChangeEvent.");
  }
}

使用 as (4):

void onEvent(Event event) {
  Place place = (event as PlaceChangeEvent).place;
  presenterProvider.display(place);
}

或者,如果您期望收到一个PlaceChangeEvent,则应该简单地更改参数的类型:

void onEvent(PlaceChangeEvent event) {
  Place place = event.place;
  presenterProvider.display(place);
}

在检查模式下,这将捕获不良类型,在未检查的模式下,当访问 event.place 时会抛出异常。这通常是首选的方式。


5

试试这个:

pce = event as PlaceChangeEvent;

谢谢@ringstaff (+1) - 但是如果event的运行时类型是PlaceChangeEvent之外的另一个Event子类怎么办?比如说我有另一个名为LogEvent的子类,在运行时event实际上是一个LogEvent(而不是PlaceChangeEvent)会发生什么?强制转换会怎样? - IAmYourFaja
再次感谢@ringstaff (+1) - 一般来说,如果Dart中的as转换失败会发生什么?是否会抛出异常,如果是,是什么类型的异常?再次感谢! - IAmYourFaja
2
@CalifornianAcorn - 如果该情况失败,它将抛出一个 TypeError 异常(类型 'Foo' 不是 'pce' 的类型 'PlaceChangeEvent' 的子类型)。 - ringstaff
由于您检查事件是否仅为PlaceChangeEvent,因此将不执行带有转换的行。换句话说,您的异常被抛出(重新发布,因为我无法编辑并且有一个大错别字)。 - Fox32

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