2013-05-02 13 views
5

Chciałbym móc przywrócić właściwość dynamiczną z mapą za pomocą odnośnika w noSuchMethod(). Jednak ostatnie zmiany powodują, że nazwa odwołania do właściwości przychodzących jest niedostępna. Rozumiem scenariusz zminifikowania, który wymaga od nas używania symboli zamiast ciągów znaków, ale powoduje to, że implementowanie zdatnych do serializacji właściwości dynamicznych jest trudne. Ktoś ma dobre pomysły, jak podejść do tego problemu?Jak zaimplementować właściwości dynamiczne w Dart?

  • Nie mogę używać nazw łańcuchów, ponieważ nazwy ciągów nie są ustalone między wywołaniami do miniarki. (To by całkowicie zepsuło serializację)

Odpowiedz

8

można uzyskać dostęp do oryginalnej nazwy z MirrorSystem.getName(symbol)

tak dynamiczny klasy może wyglądać następująco:

import 'dart:mirrors'; 

class A { 
    final _properties = new Map<String, Object>(); 

    noSuchMethod(Invocation invocation) { 
    if (invocation.isAccessor) { 
     final realName = MirrorSystem.getName(invocation.memberName); 
     if (invocation.isSetter) { 
     // for setter realname looks like "prop=" so we remove the "=" 
     final name = realName.substring(0, realName.length - 1); 
     _properties[name] = invocation.positionalArguments.first; 
     return; 
     } else { 
     return _properties[realName]; 
     } 
    } 
    return super.noSuchMethod(invocation); 
    } 
} 

main() { 
    final a = new A(); 
    a.i = 151; 
    print(a.i); // print 151 
    a.someMethod(); // throws 
} 
+0

to prawdziwa nazwa formatu, który jest dość stabilny lub czy muszę się martwić o aktualizację mojego kodu za każdym razem, gdy pojawi się nowa wersja dart? – jz87

+0

Nie wiem, czy format został określony, ale w [specyfikacji językowej] (https://www.dartlang.org/docs/spec/latest/dart-language-specification.html) istnieją odniesienia do _settera ' v = '_. Powiedziałbym więc, że jest prawie zdefiniowany. Zapraszam do zadawania pytań na liście mailingowej lub w innym pytaniu na SO :) –

0

Jeśli potrzebujesz tylko "właściwości dynamicznych", powinno wystarczyć użycie symboli jako kluczy w mapie. Jeśli chcesz również serializować tę mapę, musisz śledzić oryginalne nazwy łańcuchów i używać ich do serializacji. Podczas deserializacji, musisz utworzyć nowe symbole z tych łańcuchów.

Należy zauważyć, że wszystkie te scenariusze (iw zasadzie wszystko, co obejmuje new Symbol) wymagają kompilatora, aby utworzyć odwzorowanie oryginalnych nazw dla minifikowanych i umieścić to odwzorowanie w programie, co oczywiście powoduje, że jest on większy.

+0

tak, problem polega na tym, w jaki sposób uzyskać dostęp do oryginalnych nazw napisów? noSuchMethod nie eksponuje oryginalnego ciągu, wszystko, co dostajesz z obiektu wywołania, to symbol. – jz87

+0

Cóż, podczas umieszczania rzeczy na mapie musisz zapisywać oryginalne imiona. Edycja: o tak, zaakceptowana odpowiedź jest właściwa, istnieje odwzorowanie odwrotne. Nie pamiętałem o tym. – Ladicek

0

Można zrobić coś takiego:

import 'dart:json' as json; 

main() { 
    var t = new Thingy(); 
    print(t.bob()); 
    print(t.jim()); 
    print(json.stringify(t)); 
} 

class Thingy { 
    Thingy() { 
     _map[const Symbol('bob')] = "blah"; 
     _map[const Symbol('jim')] = "oi"; 
    } 

    final Map<Symbol, String> _map = new Map<Symbol, String>(); 

    noSuchMethod(Invocation invocation) { 
     return _map[invocation.memberName]; 
    } 

    toJson() => { 
     'bob': _map[const Symbol('bob')], 
     'jim': _map[const Symbol('jim')]}; 
} 

Aktualizacja - dynamiczny przykład:

import 'dart:json' as json; 

main() { 
    var t = new Thingy(); 
    t.add('bob', 'blah'); 
    t.add('jim', 42); 
    print(t.bob()); 
    print(t.jim()); 
    print(json.stringify(t)); 
} 

class Thingy { 
    final Map<Symbol, String> _keys = new Map<Symbol, String>(); 
    final Map<Symbol, dynamic> _values = new Map<Symbol, dynamic>(); 

    add(String key, dynamic value) { 
     _keys[new Symbol(key)] = key; 
     _values[new Symbol(key)] = value; 
    } 

    noSuchMethod(Invocation invocation) { 
     return _values[invocation.memberName]; 
    } 

    toJson() { 
     var map = new Map<String, dynamic>(); 
     _keys.forEach((symbol, name) => map[name] = _values[symbol]); 
     return map; 
    } 
} 
+0

to, czego naprawdę chcę, to coś w rodzaju obiektu Expando. Chcę móc zdefiniować Thingy ze stałymi właściwościami + dodatkowymi właściwościami, które można dodać w środowisku wykonawczym. – jz87

+0

Dodałem dynamiczny przykład - czy to masz na myśli? Zaletą tego jest to, że nie trzeba używać refleksji, co oznacza, że ​​będzie działać lepiej z dart2js. Obsługa setterów powinna być łatwa, zamiast używać add - możesz użyć kodu z powyższego przykładu Alexadresa. –

+0

Ups - najwyraźniej nie możesz obsłużyć seterów bez mirror.GetName(). –

Powiązane problemy