2013-05-02 25 views
5

Tôi muốn có thể quay lại thuộc tính động với Bản đồ bằng tra cứu trong noSuchMethod(). Tuy nhiên, các thay đổi mới nhất khiến tên tham chiếu thuộc tính đến không khả dụng. Tôi có thể hiểu được kịch bản rút gọn yêu cầu chúng tôi sử dụng Ký hiệu thay vì Strings cho tên, nhưng điều này làm cho việc triển khai các thuộc tính động có thể tuần tự trở nên khó khăn. Bất cứ ai cũng có ý tưởng tốt về cách tiếp cận vấn đề này?Làm cách nào để triển khai thuộc tính động trong Dart?

  • Tôi không thể sử dụng tên chuỗi vì tên chuỗi không được cố định giữa các cuộc gọi đến trình chỉnh sửa. (Điều này sẽ phá vỡ hoàn toàn việc tuần tự hóa)

Trả lời

8

Bạn có thể truy cập vào tên ban đầu với MirrorSystem.getName(symbol)

Vì vậy, một lớp học năng động có thể trông giống như:

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

là định dạng tên thật có điều gì đó khá ổn định hoặc tôi có phải lo lắng về việc cập nhật mã của mình mỗi khi một phiên bản phi tiêu mới xuất hiện không? – jz87

+0

Tôi không thực sự biết định dạng được chỉ định hay không trong [đặc tả ngôn ngữ] (https://www.dartlang.org/docs/spec/latest/dart-language-specification.html) có các tham chiếu đến _setter ' v = '_. Vì vậy, tôi sẽ nói nó gần như được xác định. Vui lòng hỏi trong danh sách gửi thư hoặc trong một câu hỏi SO khác :) –

0

Nếu bạn chỉ cần "thuộc tính động", sẽ đủ để sử dụng Ký hiệu làm chìa khóa trong Bản đồ. Nếu bạn cũng muốn tuần tự hóa bản đồ đó, thì bạn cần phải theo dõi các tên String ban đầu và sử dụng chúng để tuần tự hóa. Khi deserializing, bạn sẽ phải tạo ra các biểu tượng mới từ các chuỗi đó. Lưu ý rằng tất cả các kịch bản (và về cơ bản tất cả mọi thứ liên quan đến new Symbol) yêu cầu một trình biên dịch để tạo ra một ánh xạ của tên ban đầu cho những người minified và đặt bản đồ này vào chương trình, mà tất nhiên làm cho nó lớn hơn.

+0

vâng vấn đề là làm cách nào để tôi có quyền truy cập vào các tên Chuỗi gốc? noSuchMethod không phơi ra String gốc, tất cả những gì bạn nhận được từ đối tượng Invocation là Symbol. – jz87

+0

Vâng, bạn phải ghi lại tên gốc khi bạn đang đưa mọi thứ vào bản đồ. Chỉnh sửa: oh yeah, câu trả lời được chấp nhận là đúng, có một ánh xạ ngược. Không nhớ về điều đó. – Ladicek

0

Bạn có thể làm một cái gì đó như thế này:

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 - ví dụ động:

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

những gì tôi thực sự muốn là một cái gì đó giống như một đối tượng Expando. Tôi muốn có thể xác định Thingy với các thuộc tính cố định + các thuộc tính bổ sung có thể được thêm vào trong thời gian chạy. – jz87

+0

Tôi đã thêm một ví dụ động - đó là ý của bạn? Ưu điểm của việc này là bạn không phải sử dụng sự phản chiếu, điều đó có nghĩa là nó sẽ hoạt động tốt hơn với các dart2j. Nó sẽ khá dễ dàng để xử lý setters quá thay vì sử dụng add - bạn có thể sử dụng một số mã trong ví dụ của Alexadres ở trên. –

+0

Rất tiếc - bạn rõ ràng không thể xử lý các trình cài đặt không có mirror.GetName(). –

Các vấn đề liên quan