2013-05-02 1 views
5

noSuchMethod()에서 조회를 사용하여 Map으로 동적 속성을 백업하고 싶습니다. 그러나 최근의 변경으로 들어오는 속성 참조 이름을 사용할 수 없게 만듭니다. 이름에 문자열 대신 심볼을 사용하도록 요구하는 축소 시나리오를 이해할 수 있지만 직렬화 가능한 동적 속성을 구현하기가 어렵습니다. 누구나이 문제에 접근하는 좋은 방법이 있습니까?Dart에서 동적 속성을 구현하는 방법은 무엇입니까?

  • String 이름은 minifier 호출 사이에 고정되어 있지 않으므로 String 이름을 사용할 수 없습니다. (이것은 완전히 직렬화를 깨뜨릴 것입니다.)

답변

8

당신은 그래서 MirrorSystem.getName(symbol)

동적 클래스로 원래 이름에 액세스 할 수 있습니다 다음과 같이 표시 될 수 있습니다 :

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

은 매우 안정적인 실제 이름 형식이거나 새로운 버전의 다트가 나올 때마다 내 코드를 업데이트하는 것에 대해 걱정해야합니까? – jz87

+0

형식이 지정되었는지는 모르겠지만 [언어 사양] (https://www.dartlang.org/docs/spec/latest/dart-language-specification.html)에는 _setter' v ='_. 그래서 나는 그것이 거의 정의되었다고 말할 것입니다. 메일 링리스트 또는 기타 SO 질문에 대해 물어보십시오 :) –

0

"동적 속성"만 있으면 Map의 키로 Symbol을 사용하기에 충분합니다. 그 맵을 직렬화하고 싶다면 원래의 String 이름을 추적하여 직렬화에 사용해야합니다. deserialize 할 때, 당신은 그 String으로부터 새로운 Symbol을 만들어야 할 것입니다.

모든 시나리오 (기본적으로 new Symbol을 포함한 모든 것)는 원본 이름을 축소 된 이름으로 매핑 한 다음이 매핑을 프로그램에 넣으면 컴파일러가 더 커야 함을 유의해야합니다.

+0

예 문제는 어떻게 원래 String 이름에 액세스 할 수 있습니까? noSuchMethod는 원래 String을 노출시키지 않습니다. Invocation 객체에서 가져온 것은 모두 Symbol입니다. – jz87

+0

글쎄, 물건을지도에 넣을 때 원래 이름을 기록해야합니다. 편집 : 오, 그래, 허용 대답은 바로, 거기에 뒤로 매핑입니다. 그것에 대해 기억하지 못했습니다. – Ladicek

0

이 같은 것을 할 수있는 :

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

업데이트 - 동적 예 :

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

내가 정말로 원하는 것은 Expando 객체와 같은 것입니다. Thingy를 고정 속성 + 런타임에 추가 할 수있는 추가 속성으로 정의 할 수 있기를 원합니다. – jz87

+0

나는 역동적 인 예를 추가했습니다. 그게 무슨 뜻입니까? 이점은 리플렉션을 사용할 필요가 없다는 것입니다. 즉, dart2js에서 더 잘 작동합니다. add를 사용하는 대신 setter를 처리하는 것이 매우 쉬워야합니다. 위의 Alexadres 예제에서 일부 코드를 사용할 수 있습니다. –

+0

죄송합니다 - 미러가없는 세터는 분명히 처리 할 수 ​​없습니다 .GetName(). –

관련 문제