【问题标题】:call a method if it exists如果存在就调用方法
【发布时间】:2013-04-05 18:07:02
【问题描述】:

是否有一个简单的轻量级/廉价调用来确定对象是否支持命名方法? 所以,在这个 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


    【解决方案1】:

    简短的回答是“不”。 Frédéric Hamidi 提供的答案并没有错,但它在 dart2js 中不起作用(dart:mirrors 在 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
          }
      }
      

      【讨论】:

      • 在这种情况下你会如何处理JsonDecodablefromJSON()
      【解决方案3】:

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

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

      【讨论】:

        【解决方案4】:

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

        
        String json = ifHasMethodElse(() => obj.toJson(), null)
        
        dynamic ifHasMethodElse(Function closureWithCall, dynamic elseThis) {
          try {
            return closureWithCall();
          } catch (NoSuchMethodError, e) {
            return elseThis;
          }
        }
        

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            【解决方案6】:

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

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

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

            【讨论】:

              猜你喜欢
              • 2015-07-02
              • 1970-01-01
              • 1970-01-01
              • 2022-10-24
              • 1970-01-01
              • 2016-12-03
              • 2017-07-06
              • 2023-03-31
              • 2023-03-06
              相关资源
              最近更新 更多