2013-04-05 4 views
2

Есть ли простой, легкий/недорогой вызов, чтобы определить, поддерживает ли объект именованный метод? Итак, в этом 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, но я думаю, что это плохая практика и дорого?

ответ

5

Короткий ответ есть, 'нет'. Ответ Фредерика Хамиди неверен, но он не работает в dart2js (dart: зеркала в большинстве случаев не реализованы в dart2js).

Кроме того, при проверке того, реагирует ли объект на конкретный метод, очень часто встречается на других языках (например, Ruby), для меня это не кажется особенно Dart-y. Возможно, когда зеркала полностью поддерживаются в Dart, это изменится.

И трудно сказать, является ли отражение на основе зеркал «легким/недорогим». Это зависит от варианта использования и того, как вы определяете эти условия.

Я бы сказал, что ваша лучшая ставка - это вызов метода на объекте, обнаружение исключения NoSuchMethod и реализация некоторого поведения обработки ошибок по умолчанию. Это особенно важно, если вы обычно ожидаете, что метод будет присутствовать.

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

Используя несколько иной подход, я проверяю, если данный метод существует, проверив список функций экземпляра:

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.

Смежные вопросы