4

是否有一个简单、轻量级/廉价的调用来确定对象是否支持命名方法?所以,在这个 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 异常,但我认为这是不好的做法且昂贵?

4

6 回答 6

9

最简洁的答案是不'。Frédéric Hamidi 提供的答案并不正确,但它在 dart2js 中不起作用(dart:mirrors 在 dart2js 中很大程度上未实现)。

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

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

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

于 2013-04-05T19:32:38.450 回答
3

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

abstract class JsonEncodable {
    Map toJSON();
}

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

class Foo implements JsonEncodable {
    Map toJSON() {
        // toJSON implementation
    }
}
于 2014-04-16T05:05:19.563 回答
3

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


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

dynamic ifHasMethodElse(Function closureWithCall, dynamic elseThis) {
  try {
    return closureWithCall();
  } catch (NoSuchMethodError, e) {
    return elseThis;
  }
}
于 2020-07-25T10:20:49.647 回答
2

使用dart:mirrors,您应该能够编写如下内容:

bool respondsTo(dynamic obj, String methodName)
{
    var mirror = reflect(obj);
    return mirror.type.methods.values.map((MethodMirror method) => method.simpleName)
                                     .contains(methodName);
}
于 2013-04-05T18:36:45.583 回答
1

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

InstanceMirror im = reflect(this);
Symbol fn = new Symbol('$functionName');
if (im.type.instanceMembers.keys.contains(fn)) {
  im.invoke(fn, params);
}
于 2014-09-12T20:39:25.403 回答
0

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

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

我仅将其用于调试/故障排除目的——我从未将这段代码投入生产。理想情况下,您最好定义某种接口并将其作为您的obj而不是动态的,正如@thetrompf 建议的那样。

于 2018-03-02T02:07:44.977 回答