如果存在,则调用方法

时间:2013-04-05 18:07:02

标签: dart dart-mirrors

是否有一个简单的轻量级/廉价调用来确定对象是否支持命名方法? 所以,在这个obj.respondsTo会很棒。

dynamic _toJson(dynamic obj) {
  return obj.respondsTo('toJson'))? obj.toJson() : obj;
}

class Foo {
  String foo = "Foo.foo";
  Bar bar = new Bar();
  Map toJson() {
    return {
      "foo" : _toJson(foo),
      "bar" : _toJson(bar)
    };
  }
}

一种替代方法是调用它并捕获noSuchMethod异常,但我认为这是不好的做法且价格昂贵?

6 个答案:

答案 0 :(得分:6)

简短的回答是'不'。 FrédéricHamidi提供的答案并不正确,但它在dart2js中不起作用(dart:镜子在dart2js中基本上没有实现)。

此外,在检查对象是否响应特定方法时,在其他语言(例如Ruby)中非常常见,但对我来说它似乎并不特别Dart-y。也许一旦Dart完全支持镜像,这将会改变。

很难说基于镜子的反射是否“轻巧/便宜”。这取决于用例以及如何定义这些术语。

我想说最好的办法是调用对象上的方法,捕获NoSuchMethod异常,并实现一些默认的错误处理行为。如果您通常希望该方法存在,这尤其有意义。

答案 1 :(得分:2)

如果对象是接口类型,则可以在测试时使用抽象方法定义接口/抽象类,然后调用您现在知道的方法。

abstract class JsonEncodable {
    Map toJSON();
}

Object _toJson(Object obj) {
    return (obj is JsonEncodable)? obj.toJson() : obj;
}

class Foo implements JsonEncodable {
    Map toJSON() {
        // toJSON implementation
    }
}

答案 2 :(得分:1)

使用dart:mirrors,您应该可以编写如下内容:

bool respondsTo(dynamic obj, String methodName)
{
    var mirror = reflect(obj);
    return mirror.type.methods.values.map((MethodMirror method) => method.simpleName)
                                     .contains(methodName);
}

答案 3 :(得分:1)

使用稍微不同的方法,我通过检查实例函数列表来检查给定方法是否存在:

InstanceMirror im = reflect(this);
Symbol fn = new Symbol('$functionName');
if (im.type.instanceMembers.keys.contains(fn)) {
  im.invoke(fn, params);
}

答案 4 :(得分:0)

不是轻量级,但不需要mirrors(并且在重新阅读已接受的答案后,它基本上是接受的答案暗示的可能性):

dynamic _toJson(dynamic obj) {
  try {
    return obj.toJson();
  } catch(NoSuchMethodError) {
    return obj;
  }
}

我只是将它用于调试/故障排除目的 - 我从未将此代码投入生产。理想情况下,你最好定义某种界面并将其作为obj而不是像@thetrompf建议的那样传递。

答案 5 :(得分:0)

这是一种解决方法,但是我使用了一个基本上是内联try catch的小助手:


String json = ifHasMethodElse(() => obj.toJson(), null)

dynamic ifHasMethodElse(Function closureWithCall, dynamic elseThis) {
  try {
    return closureWithCall();
  } catch (NoSuchMethodError, e) {
    return elseThis;
  }
}