noSuchMethod method
Invoked when a nonexistent method or property is accessed.
A dynamic member invocation can attempt to call a member which doesn't exist on the receiving object. Example:
dynamic object = 1;
object.add(42); // Statically allowed, run-time error
This invalid code will invoke the noSuchMethod
method
of the integer 1
with an Invocation representing the
.add(42)
call and arguments (which then throws).
Classes can override noSuchMethod to provide custom behavior for such invalid dynamic invocations.
A class with a non-default noSuchMethod invocation can also omit implementations for members of its interface. Example:
class MockList<T> implements List<T> {
noSuchMethod(Invocation invocation) {
log(invocation);
super.noSuchMethod(invocation); // Will throw.
}
}
void main() {
MockList().add(42);
}
This code has no compile-time warnings or errors even though
the MockList
class has no concrete implementation of
any of the List
interface methods.
Calls to List
methods are forwarded to noSuchMethod
,
so this code will log
an invocation similar to
Invocation.method(#add, [42])
and then throw.
If a value is returned from noSuchMethod
,
it becomes the result of the original invocation.
If the value is not of a type that can be returned by the original
invocation, a type error occurs at the invocation.
The default behavior is to throw a NoSuchMethodError.
Implementation
@override
dynamic noSuchMethod(Invocation invocation) {
final m = _methods[invocation.memberName];
if (m == null) {
throw NoSuchMethodError.withInvocation(this, invocation);
}
final c = m.outputType.qualifiedName.toString() == 'Symbol("void")'
? reflect(Completer<void>())
: (reflectType(Completer, [m.outputType.reflectedType]) as ClassMirror)
.newInstance(Symbol(''), []);
_client
.invoke(
m.name,
invocation.positionalArguments.isEmpty
? null
: invocation.positionalArguments.single)
.then(
(v) {
if (m.outputIsJsonNative) return v;
return m.outputClass!.newInstance(Symbol('fromJson'), [v]).reflectee;
},
).then(
(r) {
c.invoke(Symbol('complete'), [r]);
},
onError: (e, st) {
c.invoke(Symbol('completeError'), [e, st]);
},
);
return c.getField(Symbol('future')).reflectee;
}