Proxy 如何使用dart实现委托/代理?

Proxy 如何使用dart实现委托/代理?,proxy,delegates,dart,dart-mirrors,nosuchmethod,Proxy,Delegates,Dart,Dart Mirrors,Nosuchmethod,我有两个类Parser和Proxy,当我从Parser调用一个不存在的方法时,它会将它委托给Proxy类 我的代码: 类解析器{ noSuchMethod(调用调用){ //如何将“调用”传递给“代理”??? } } 类代理{ 静态字符串hello(){返回“hello”;} 静态字符串world(){返回“world”;} } 当我写作时: var parser=new parser(); 打印(parser.hello()); 它将打印: hello 你必须使用省道:镜子。下面是如何做

我有两个类
Parser
Proxy
,当我从
Parser
调用一个不存在的方法时,它会将它委托给
Proxy

我的代码:

类解析器{
noSuchMethod(调用调用){
//如何将“调用”传递给“代理”???
}
}
类代理{
静态字符串hello(){返回“hello”;}
静态字符串world(){返回“world”;}
}
当我写作时:

var parser=new parser();
打印(parser.hello());
它将打印:

hello
你必须使用省道:镜子。下面是如何做到的:

导入“dart:mirrors”;
类解析器{
noSuchMethod(调用调用){
ClassMirror cm=反射等级(代理);
返回cm.invoke(invocation.memberName
,invocation.positionalArguments
/*,invocation.namedArguments*///尚未实现
).被反射者;
}
}
类代理{
静态字符串hello(){返回“hello”;}
静态字符串world(){返回“world”;}
}
main(){
var parser=newparser();
打印(parser.hello());
print(parser.world());
}

Alexandre的回答是正确的,但我想补充一点

我假设对
代理的委托是一个实现细节,我们不希望用户暴露于此。在这种情况下,我们应该处理在
parser
上调用
Proxy
不支持的方法的情况。现在,如果您这样做:

void main(){
var parser=newparser();
打印(parser.foo());
}
您将得到以下错误:

未处理的异常:
镜像执行期间的编译时错误:
我会用
noSuchMethod
编写代码,但有点不同。在委托给
Proxy
之前,我会检查
Proxy
是否支持我将要调用的方法。如果
Proxy
支持它,我将调用
Proxy
上的方法,正如Alexandre在回答中所描述的那样。如果
Proxy
不支持该方法,我将抛出
NoSuchMethodError

以下是答案的修订版本:

导入“dart:mirrors”;
类解析器{
noSuchMethod(调用调用){
ClassMirror cm=反射等级(代理);
if(cm.methods.keys.contains(invocation.memberName)){
返回cm.invoke(invocation.memberName
,invocation.positionalArguments
/*,invocation.namedArguments*///尚未实现
).被反射者;
}
抛出新的NoSuchMethodError(此,
_symbolToString(invocation.memberName),
invocation.positionalArguments,
_symbolMapToStringMap(invocation.namedArguments));
}
}
字符串_symbolToString(Symbol)=>MirrorSystem.getName(Symbol);
地图_symbolMapToStringMap(地图地图地图){
if(map==null)返回null;
var result=newmap();
map.forEach((符号键,值){
结果[_symbolToString(键)]=值;
});
返回结果;
}
类代理{
静态字符串hello(){返回“hello”;}
静态字符串world(){返回“world”;}
}
main(){
var parser=newparser();
打印(parser.hello());
print(parser.world());
打印(parser.foo());
}
下面是运行此代码的输出:

你好 世界 未处理的异常: NoSuchMethodError:找不到方法:“foo” 接收方:“解析器”的实例 论点:[]
我还想补充一点,如果您希望委托的一组内容是固定的,并且您可以合理地对其进行硬编码,那么您可以避免使用镜像。如果您使用的是静态方法,那么这特别容易,但我不清楚您为什么要在这里这样做。我认为下面的代码对实例方法和静态方法都有效,但是我在没有实际尝试的情况下输入了这段代码

函数查找方法(代理p,符号名){
如果(name==const Symbol(“hello”))返回p.hello;
if(name==常量符号(“world”))返回p.world;
扔“aaaagh”;
}
noSuchMethod(调用)=>
apply(lookupMethod(Proxy,invocation.memberName),
调用(参数);

如果转发的方法集发生更改,这是脆弱的,但如果您使用镜像(此时禁用几乎所有树抖动),则可能有助于避免代码大小增加。

此示例还可以帮助您理解:

void main(){
var car=新CarProxy(新ProxyObjectImpl(“car”);
试验车;
var person=新PersonProxy(新ProxyObjectImpl(“person”);
测试人员(人);
}
无效测试车(汽车){
印刷品(汽车、发动机);
}
无效测试人员(人员){
印刷品(人、年龄);
打印(个人姓名);
}
抽象类汽车{
串接电机;
}
抽象类人{
得到年龄;
字符串获取名称;
}
CarProxy类工具车{
最终代理对象\u代理;
CarProxy(本代理);
noSuchMethod(调用调用){
return\u proxy.handle(调用);
}
}
类PersonProxy实现Person{
最终代理对象\u代理;
个人代理人(本代理人);
noSuchMethod(调用调用){
return\u proxy.handle(调用);
}
}
抽象类ProxyObject{
动态句柄(调用);
}
类ProxyObjectImpl实现ProxyObject{
字符串类型;
int-id;
地图属性;
ProxyObjectImpl(this.type,[this.id]){
properties=ProxyManager.getProperties(类型);
}
动态句柄(调用){
var memberName=invocation.memberName;
if(invocation.isGetter){
if(properties.containsKey(memberName)){
返回属性[memberName];
}
}
抛出“运行时错误:$type没有$memberName成员”;
}
}
类代理管理器{
静态映射getProperties(字符串名称){
映射属性=新映射();
交换机(名称){
“汽车”案例:
属性[新符号('motor')]='xPowerDrive2013';
打破
案例“人”:
属性[新符号(‘年龄’)]=42;
属性[新符号('name')]='Bob