Что такое функция Dart "Expando", что она делает?

Недавно видели термин "Expando" с Dart. Звучит интересно. API не дал мне большой подсказки.

Пример или два могут быть полезны!

(Не уверен, что это связано, но я больше всего беспокоюсь о способе добавления методов (геттеров) и/или переменных в класс. Надеясь, что это может быть ключом к решению этой проблемы. (Подсказка: я использую метод Nosuchmethod теперь и хотите иметь возможность вернуть значение необоснованного метода.))

Спасибо заранее,

_swarmii

Ответ 1

Expandos позволяет вам связывать объекты с другими объектами. Один очень полезный пример этого - элемент HTML DOM, который сам по себе не может быть подклассифицирован. Пусть сделайте верхний уровень expando, чтобы добавить некоторую функциональность к элементу - в этом случае подпись функции, указанную в инструкции 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');
}

Ответ 2

Просто, чтобы уточнить разницу между expando и maps: как указано в groups, expando имеет слабые ссылки.
 Это означает, что ключ может быть собран в мусор, даже если он все еще присутствует в expando (пока нет других ссылок на него).

Для всех других целей и целей это карта.

Ответ 3

Я играл с ним немного. Вот что у меня есть.

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