IAmYourFaja
IAmYourFaja

Reputation: 56864

Dart typecasting error

I have an abstract class Event and a concrete subclass that extends it called PlaceChangeEvent. Inside an event listener, I have the following code:

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);
}

So if the runtime type of event is PlaceChangeEvent, then I need to cast the event to that type so that I can access its properties. But I'm getting a compiler error on the typecast, stating:

A value of type 'Type' cannot be assigned to a variable of type 'PlaceChangeEvent'

Where am I going wrong, and what do I need to do to fix it?

Upvotes: 7

Views: 11063

Answers (2)

Florian Loitsch
Florian Loitsch

Reputation: 8128

In 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.

For your example this boils down to:

No explicit check (1):

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

With an 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.");
  }
}

Using as (4):

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

Alternatively, if you expect to receive a PlaceChangeEvent, you should simply change the type of the argument:

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

In checked mode this will catch bad types, and in unchecked mode it will throw when accessing event.place. This is generally the preferred way.

Upvotes: 8

ringstaff
ringstaff

Reputation: 2325

Try this:

pce = event as PlaceChangeEvent;

Upvotes: 5

Related Questions