我希望能夠使用noSuchMethod()中的查找來支持Map的動態屬性。但是,最新更改會使傳入屬性引用名稱不可用。我可以理解縮小方案要求我們使用符號而不是字符串作爲名稱,但是這使得實現可序列化的動態屬性變得困難。任何人都有如何解決這個問題的好主意?如何在Dart中實現動態屬性?
- 我無法使用字符串名稱,因爲字符串名稱在調用縮小器之間不固定。 (這將完全破壞序列化)
我希望能夠使用noSuchMethod()中的查找來支持Map的動態屬性。但是,最新更改會使傳入屬性引用名稱不可用。我可以理解縮小方案要求我們使用符號而不是字符串作爲名稱,但是這使得實現可序列化的動態屬性變得困難。任何人都有如何解決這個問題的好主意?如何在Dart中實現動態屬性?
您可以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
}
如果您只需要「動態屬性」,它應該足以在地圖中使用符號作爲鍵。如果您還想序列化該映射,則需要跟蹤原始字符串名稱並將其用於序列化。反序列化時,你必須從這些字符串中創建新的符號。
請注意,所有這些場景(基本上涉及new Symbol
的所有內容)都需要一個編譯器來創建原始名稱與縮小比例的映射,並將該映射放入程序中,這當然會使其變得更大。
你可以做這樣的事情:
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;
}
}
我真正想要的就像是一個Expando對象。我希望能夠使用固定屬性和可以在運行時添加的其他屬性來定義Thingy。 – jz87 2013-05-02 06:06:28
我已經添加了一個動態示例 - 是您的意思?這樣做的好處是您不必使用反射,這意味着它可以更好地與dart2js配合使用。它也應該很容易處理setter,而不是使用add - 你可以在上面的Alexadres的例子中使用一些代碼。 – 2013-05-02 21:38:25
糟糕 - 你顯然無法處理沒有mirror.GetName()的setter。 – 2013-05-02 22:01:51
是真正的名字格式,它相當穩定,或者每當新版本的dart出現時,我不得不擔心更新我的代碼? – jz87 2013-05-02 07:47:44
我真的不知道格式是否被指定,但在[語言規範](https://www.dartlang.org/docs/spec/latest/dart-language-specification.html)中有引用_setter' v ='_。所以我會說它幾乎被定義。隨意問在郵件列表或其他SO問題:) – 2013-05-02 08:39:09