Reputation: 56864
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
Reputation: 8128
In Dart
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
.
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;
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.
}
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