6

と の 2 つのクラスがParserあり、存在しないProxyからメソッドを呼び出すと、それはクラスにデリゲートされます。ParserProxy

私のコード:

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
4

4 に答える 4

10

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());
}
于 2013-07-03T08:31:29.997 に答える
6

アレクサンドルの答えは正しいですが、何かを追加したいと思います。

への委任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場合は、 .ProxyNoSuchMethodError

回答の改訂版は次のとおりです。

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: []
于 2013-07-03T14:36:15.947 に答える
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);

転送されるメソッドのセットが変更された場合、これは脆弱ですが、ミラーを使用するとコード サイズの増加を回避するのに役立つ場合があります (現時点では、ほとんどすべてのツリー シェーキングが無効になっています)。

于 2013-07-03T17:03:21.650 に答える
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;
  }
}
于 2013-07-04T06:38:23.040 に答える