2013-05-02 11 views
5

Vorrei poter eseguire il backup di una proprietà dinamica con una mappa utilizzando una ricerca in noSuchMethod(). Tuttavia, le ultime modifiche rendono il nome di riferimento della proprietà in entrata non disponibile. Riesco a capire lo scenario di minificazione che ci impone di utilizzare Simboli piuttosto che stringhe per i nomi, ma ciò rende difficile l'implementazione di proprietà dinamiche serializzabili. Qualcuno ha buone idee su come affrontare questo problema?Come implementare le proprietà dinamiche in Dart?

  • Non riesco a utilizzare i nomi delle stringhe poiché i nomi delle stringhe non sono corretti tra le chiamate al minificatore. (Ciò interromperà completamente la serializzazione)

risposta

8

È possibile accedere al nome originale con MirrorSystem.getName(symbol)

Quindi una classe dinamica potrebbe apparire come:

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

è il formato del nome reale qualcosa che è abbastanza stabile o devo preoccuparmi di aggiornare il mio codice ogni volta che esce una nuova versione di dardo? – jz87

+0

Non so davvero se il formato è specificato ma nella [specifica del linguaggio] (https://www.dartlang.org/docs/spec/latest/dart-language-specification.html) ci sono riferimenti a _setter ' v = '_. Quindi direi che è quasi definito. Sentiti libero di chiedere sulla mailing list o in un'altra domanda SO :) –

0

Se sono necessarie solo "proprietà dinamiche", dovrebbe essere sufficiente utilizzare Simboli come chiavi nella Mappa. Se si desidera serializzare tale mappa, è necessario tenere traccia dei nomi String originali e utilizzarli per la serializzazione. Quando deserializzi, dovresti creare nuovi simboli da quelle stringhe.

Si noti che tutti questi scenari (e sostanzialmente tutto ciò che riguarda lo new Symbol) richiedono a un compilatore di creare una mappatura dei nomi originali a quelli miniati e inserire questa mappatura nel programma, che ovviamente lo rende più grande.

+0

sì il problema è come ottengo l'accesso ai nomi di stringa originali? noSuchMethod non espone la Stringa originale, tutto ciò che ottieni dall'oggetto Invocazione è il Simbolo. – jz87

+0

Bene, devi registrare i nomi originali quando metti le cose nella mappa. Modifica: oh sì, la risposta accettata è giusta, c'è una mappatura all'indietro. Non me lo ricordavo. – Ladicek

0

Si potrebbe fare qualcosa di simile:

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

Update - Esempio dinamica:

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

quello che voglio veramente è qualcosa come un oggetto Expando. Voglio essere in grado di definire Thingy con proprietà fisse + proprietà aggiuntive che possono essere aggiunte in fase di runtime. – jz87

+0

Ho aggiunto un esempio dinamico - è questo che intendi? Il vantaggio di questo è che non è necessario utilizzare il reflection, il che significa che funzionerà meglio con dart2js. Dovrebbe essere abbastanza facile gestire anche i setter invece di usare add - è possibile utilizzare parte del codice nell'esempio di Alexadres sopra. –

+0

Oops: ovviamente non puoi gestire setter senza mirror.GetName(). –

Problemi correlati