如果存在,则调用方法

问题描述 投票:2回答:5

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

dart dart-mirrors
5个回答
6
投票

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

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

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

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


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
    }
}

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);
}

1
投票

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

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

0
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.