О чем особенность Dart "Expando", что она делает?
Давно видел термин "Expando", использованный недавно с Dart. Звучит интересно. API не дал мне большой подсказки.
Пример или два могут быть наиболее полезными!
(Не уверен, что это связано, но мне больше всего нужен способ добавить методы (получатели) и / или переменные в класс. Надеясь, что это может быть ключом к решению этой проблемы. (Подсказка: я использую метод Nosuchmethod сейчас и хочу иметь возможность вернуть значение необнаруженного метода.))
Заранее спасибо,
_swarmii
3 ответа
Расширения позволяют связывать объекты с другими объектами. Одним из очень полезных примеров этого является HTML-элемент DOM, который сам не может быть разделен на подклассы. Давайте сделаем команду эксплойта верхнего уровня, чтобы добавить некоторую функциональность элементу - в этом случае сигнатура функции, заданная в операторе typedef:
typedef CustomFunction(int foo, String bar);
Expando<CustomFunction> domFunctionExpando = new Expando<CustomFunction>();
Теперь, чтобы использовать это:
main(){
// Assumes dart:html is imported
final myElement = new DivElement();
// Use the expando on our DOM element.
domFunctionExpando[myElement] = someFunc;
// Now that we've "attached" the function to our object,
// we can call it like so:
domFunctionExpando[myElement](42, 'expandos are cool');
}
void someFunc(int foo, String bar){
print('Hello. $foo $bar');
}
Просто чтобы прояснить разницу между эксплоо и картами: как сообщается в группах, у экспандо есть слабые ссылки.
Это означает, что ключ может быть подвергнут сборке мусора, даже если он все еще присутствует в эксплооне (если на него нет других ссылок).
Для всех остальных целей это карта.
Я немного поиграл с этим. Вот что у меня есть.
import 'dart:html';
const String cHidden = 'hidden';
class ExpandoElement {
static final Expando<ExpandoElement> expando =
new Expando<ExpandoElement>("ExpandoElement.expando");
final Element element;
const ExpandoElement._expand(this.element);
static Element expand(Element element) {
if (expando[element] == null)
expando[element] = new ExpandoElement._expand(element);
return element;
}
// bool get hidden => element.hidden; // commented out to test noSuchMethod()
void set hidden(bool hidden) {
if (element.hidden = hidden)
element.classes.add(cHidden);
else
element.classes.remove(cHidden);
}
noSuchMethod(InvocationMirror invocation) => invocation.invokeOn(element);
}
final Expando<ExpandoElement> x = ExpandoElement.expando;
Element xquery(String selector) => ExpandoElement.expand(query(selector));
final Element input = xquery('#input');
void main() {
input.classes.remove(cHidden);
assert(!input.classes.contains(cHidden));
input.hidden = true;
assert(x[input].hidden); // Dart Editor warning here, but it's still true
assert(!input.classes.contains(cHidden)); // no effect
input.hidden = false;
assert(!x[input].hidden); // same warning, but we'll get input.hidden via noSuchMethod()
assert(!input.classes.contains(cHidden));
x[input].hidden = true;
assert(input.hidden); // set by the setter of ExpandoElement.hidden
assert(input.classes.contains(cHidden)); // added by the setter
assert(x[input].hidden);
assert(x[input].classes.contains(cHidden)); // this is input.classes
x[input].hidden = false;
assert(!input.hidden); // set by the setter
assert(!input.classes.contains(cHidden)); // removed by the setter
assert(!x[input].hidden);
assert(!x[input].classes.contains(cHidden));
// confused?
assert(input is Element);
assert(x[input] is! Element); // is not
assert(x[input] is ExpandoElement);
assert(x is Expando<ExpandoElement>);
}