我有两个类Parser
和Proxy
,当我从Parser
调用一个不存在的方法时,它会将它委托给Proxy
类。< / p>
我的代码:
class Parser {
noSuchMethod(Invocation invocation) {
// how to pass the `invocation` to `Proxy`???
}
}
class Proxy {
static String hello() { return "hello"; }
static String world() { return "world"; }
}
当我写的时候:
var parser = new Parser();
print(parser.hello());
它将打印:
hello
答案 0 :(得分:7)
您必须使用 dart:mirrors 。这是怎么做的:
import 'dart:mirrors';
class Parser {
noSuchMethod(Invocation invocation) {
ClassMirror cm = reflectClass(Proxy);
return cm.invoke(invocation.memberName
, invocation.positionalArguments
/*, invocation.namedArguments*/ // not implemented yet
).reflectee;
}
}
class Proxy {
static String hello() { return "hello"; }
static String world() { return "world"; }
}
main(){
var parser = new Parser();
print(parser.hello());
print(parser.world());
}
答案 1 :(得分:4)
Alexandre的回答是正确的,但我想补充一些内容。
我假设Proxy
的委托是一个实现细节,我们不希望用户接触它。在这种情况下,我们应该对parser
不支持的Proxy
上调用方法的情况进行一些处理。现在,如果你这样做:
void main() {
var parser = new Parser();
print(parser.foo());
}
您收到此错误:
Unhandled exception:
Compile-time error during mirrored execution: <Dart_Invoke: did not find static method 'Proxy.foo'.>
我会在noSuchMethod
中编写一些不同的代码。在委派给Proxy
之前,我会检查Proxy
是否支持我要调用的方法。如果Proxy
支持它,我会调用Proxy
上的方法,正如亚历山大在他的回答中所描述的那样。如果Proxy
不支持该方法,我会抛出NoSuchMethodError
。
以下是答案的修订版本:
import 'dart:mirrors';
class Parser {
noSuchMethod(Invocation invocation) {
ClassMirror cm = reflectClass(Proxy);
if (cm.methods.keys.contains(invocation.memberName)) {
return cm.invoke(invocation.memberName
, invocation.positionalArguments
/*, invocation.namedArguments*/ // not implemented yet
).reflectee;
}
throw new NoSuchMethodError(this,
_symbolToString(invocation.memberName),
invocation.positionalArguments,
_symbolMapToStringMap(invocation.namedArguments));
}
}
String _symbolToString(Symbol symbol) => MirrorSystem.getName(symbol);
Map<String, dynamic> _symbolMapToStringMap(Map<Symbol, dynamic> map) {
if (map == null) return null;
var result = new Map<String, dynamic>();
map.forEach((Symbol key, value) {
result[_symbolToString(key)] = value;
});
return result;
}
class Proxy {
static String hello() { return "hello"; }
static String world() { return "world"; }
}
main(){
var parser = new Parser();
print(parser.hello());
print(parser.world());
print(parser.foo());
}
以下是运行此代码的输出:
hello
world
Unhandled exception:
NoSuchMethodError : method not found: 'foo'
Receiver: Instance of 'Parser'
Arguments: []
答案 2 :(得分:3)
我还要补充一点,如果你想要委托的东西是固定的,你可以避免使用镜像,你可以合理地硬编码。如果你使用的是静态方法,这一点特别容易,但我不清楚为什么你这样做。我认为以下内容适用于实例方法和静态方法,但我输入的代码却没有实际尝试...
Function lookupMethod(Proxy p, Symbol name) {
if (name == const Symbol("hello")) return p.hello;
if (name == const Symbol("world")) return p.world;
throw "Aaaaaagh";
}
noSuchMethod(invocation) =>
Function.apply(lookupMethod(Proxy, invocation.memberName),
invocation.positionalArguments);
如果转发的方法集发生变化,这很脆弱,但如果你使用镜像(目前几乎所有的树木都不能停止),可能有助于避免代码大小的增加。
答案 3 :(得分:1)
此示例也可以帮助您理解:
void main() {
var car = new CarProxy(new ProxyObjectImpl('Car'));
testCar(car);
var person = new PersonProxy(new ProxyObjectImpl('Person'));
testPerson(person);
}
void testCar(Car car) {
print(car.motor);
}
void testPerson(Person person) {
print(person.age);
print(person.name);
}
abstract class Car {
String get motor;
}
abstract class Person {
int get age;
String get name;
}
class CarProxy implements Car {
final ProxyObject _proxy;
CarProxy(this._proxy);
noSuchMethod(Invocation invocation) {
return _proxy.handle(invocation);
}
}
class PersonProxy implements Person {
final ProxyObject _proxy;
PersonProxy(this._proxy);
noSuchMethod(Invocation invocation) {
return _proxy.handle(invocation);
}
}
abstract class ProxyObject {
dynamic handle(Invocation invocation);
}
class ProxyObjectImpl implements ProxyObject {
String type;
int id;
Map<Symbol, dynamic> properties;
ProxyObjectImpl(this.type, [this.id]) {
properties = ProxyManager.getProperties(type);
}
dynamic handle(Invocation invocation) {
var memberName = invocation.memberName;
if(invocation.isGetter) {
if(properties.containsKey(memberName)) {
return properties[memberName];
}
}
throw "Runtime Error: $type has no $memberName member";
}
}
class ProxyManager {
static Map<Symbol, dynamic> getProperties(String name) {
Map<Symbol, dynamic> properties = new Map<Symbol, dynamic>();
switch(name) {
case 'Car':
properties[new Symbol('motor')] = 'xPowerDrive2013';
break;
case 'Person':
properties[new Symbol('age')] = 42;
properties[new Symbol('name')] = 'Bobby';
break;
default:
throw new StateError('Entity not found: $name');
}
return properties;
}
}