2012-03-11 31 views
14

Tôi muốn có thể truy cập các giá trị thuộc tính trong một đối tượng như từ điển, sử dụng tên thuộc tính làm khóa. Tôi không thực sự quan tâm nếu các giá trị được trả về như các đối tượng, do đó, Dictionary<string, object> là tốt. Đây là việc sử dụng dự định:Đối tượng xử lý Giống như từ điển thuộc tính trong C#

object person = new { Name: "Bob", Age: 45 }; 
IDictionary<string, object> lookup = new PropertyDictionary(person); 
string name = (string)person["Name"]; 
person["Age"] = (int)person["Age"] + 1; // potentially editable 

tôi sắp sửa thực hiện lớp của riêng tôi cho điều này, nhưng sau đó tôi bắt đầu nhận thấy lớp học như DynamicObject thực hiện các giao diện IDictionary, khiến suy nghĩ này đã và đang được thực hiện đối với tôi ở đâu đó.

Điều tôi muốn tương tự với chức năng được ASP.NET MVC sử dụng, cho phép sử dụng các loại ẩn danh để đặt thuộc tính thẻ HTML. Tôi có rất nhiều lớp học sử dụng từ điển làm nguồn dữ liệu, nhưng hầu hết thời gian tôi cũng có thể truyền vào các đối tượng.

Vì mục đích này là dành cho mục đích chung library, tôi nghĩ tôi sẽ tạo một lớp có thể tái sử dụng được trang trí đơn giản một đối tượng có giao diện IDictionary. Nó sẽ cứu tôi khỏi việc tạo ra một vụ nổ quá tải.

+0

Something như Indexing trên MSDN ... http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx – Lloyd

Trả lời

18

Tôi không tin rằng có một built-in loại Net như thế này đã có trong .Net framework. Có vẻ như bạn thực sự muốn tạo một đối tượng cư xử rất giống một đối tượng Javascript. Nếu có thì xuất phát từ DynamicObject có thể là lựa chọn đúng đắn. Nó cho phép bạn tạo một đối tượng khi được gói với dynamic cho phép bạn liên kết trực tiếp obj.Name hoặc qua chỉ mục obj["Name"].

public class PropertyBag : DynamicObject { 
    private object _source; 
    public PropertyBag(object source) { 
    _source = source; 
    } 
    public object GetProperty(string name) { 
    var type = _source.GetType(); 
    var property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 
    return property.GetValue(_source, null); 
    } 
    public override bool TryGetMember(GetMemberBinder binder, out object result) { 
    result = GetProperty(binder.Name); 
    return true; 
    } 
    public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) { 
    result = GetProperty((string)indexes[0]); 
    return true; 
    } 
} 

Bạn có thể sử dụng để quấn bất kỳ loại và sử dụng cả hai cú pháp indexer và tên để có được các tính chất

var student = new Student() { FirstName = "John", LastName = "Doe" }; 
dynamic bag = new PropertyBag(student); 
Console.WriteLine(bag["FirstName"]); // Prints: John 
Console.WriteLine(bag.FirstName);  // Prints: John 
+0

Tôi đã làm một cái gì đó tương tự, nhưng không thừa hưởng DynamicObject. Tôi chỉ thừa hưởng từ IDictionary và chỉ hỗ trợ lập chỉ mục, vì đó là tất cả những gì tôi cần. –

+0

Bạn đã xem ExpandoObject chưa? http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx – Scott

+1

ExpandoObject chỉ hoạt động nếu bạn bắt đầu từ đầu. –

1

từ khóa động có thể là một tùy chọn cho bạn. nó sử dụng thời gian chạy ngôn ngữ động. Khi chạy, nó cố gắng khớp với loại có sẵn gần nhất trong chương trình. Nếu nó không thể, sau đó nó chuyển đổi kiểu động thành đối tượng dictionay, trong đó khóa là tên thuộc tính và giá trị là giá trị của thuộc tính.

làm theo các liên kết của MSDN:

Using dynamic keyword in C#
dynamic (C# Reference)
DLR Overview
usage of dynamic sample walkthough page

+0

Vấn đề duy nhất là tôi sẽ cần phải sửa đổi tất cả các hiện thực của tôi để chấp nhận năng động. Ngoài ra, tôi không chắc chắn làm thế nào tôi sẽ tham chiếu một tài sản theo tên, kể từ obj ["Tên"] sẽ được hiểu là một cuộc gọi đến một chỉ mục trên năng động. –

+0

bạn không thể trực tiếp truy cập từ điển? có việc thực hiện của riêng bạn có thể làm cho mọi thứ rối tung lên ... Những gì tôi cam kết là bạn muốn một lớp được tự động chuyển đổi sang từ điển thông qua chỉ mục? bạn đã thử tạo chỉ mục với tham số kiểu chuỗi chưa? – Uday0119

+0

Tôi muốn bọc một đối tượng, không sao chép nó vào từ điển. Ý tưởng là để vượt qua một đối tượng mà một IDictionary được mong đợi. Bằng cách đó tôi có thể sử dụng các loại vô danh mà từ điển được mong đợi. –

8

tôi có phương pháp mở rộng này, có lẽ là đơn giản nhất nó có thể nhận được:

public static Dictionary<string, object> ToPropertyDictionary(this object obj) 
{ 
    var dictionary = new Dictionary<string, object>(); 
    foreach (var propertyInfo in obj.GetType().GetProperties()) 
     if (propertyInfo.CanRead && propertyInfo.GetIndexParameters().Length == 0) 
      dictionary[propertyInfo.Name] = propertyInfo.GetValue(obj, null); 
    return dictionary; 
} 

Bây giờ bạn có thể làm:

object person = new { Name = "Bob", Age = 45 }; 
var lookup = person.ToPropertyDictionary(); 
string name = (string)lookup["Name"]; 
lookup["Age"] = (int)lookup["Age"] + 1; // indeed editable 

Lưu ý:

  1. rằng từ điển này là trường hợp nhạy cảm (bạn trivially có thể mở rộng nó đi qua bên phải StringComparer).

  2. rằng nó bỏ qua các chỉ mục (cũng là các thuộc tính) nhưng tùy thuộc vào bạn để làm việc trên đó.

  3. rằng phương pháp này không phải là chung chung xem xét nó không giúp đấm bốc vì nội bộ nó gọi là obj.GetType, do đó, hộp đó anyway tại thời điểm đó.

  4. bạn chỉ nhận được các thuộc tính "có thể đọc" (nếu không bạn không nhận được các giá trị được giữ trong đó). Vì bạn muốn nó "có thể ghi", bạn cũng nên sử dụng cờ CanWrite.

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