2011-02-08 26 views
129

tôi muốn truy cập giá trị của một dynamic C# bất động sản với một chuỗi:Nhận giá trị của bất động sản năng động C# qua chuỗi

dynamic d = new { value1 = "some", value2 = "random", value3 = "value" };

Làm thế nào tôi có thể nhận được giá trị của d.value2 ("ngẫu nhiên ") nếu tôi chỉ có" value2 "dưới dạng chuỗi? Trong javascript, tôi có thể làm d ["value2"] để truy cập vào giá trị ("ngẫu nhiên"), nhưng tôi không chắc chắn làm thế nào để làm điều này với C# và phản ánh. Gần nhất tôi đến là:

d.GetType().GetProperty("value2") ... nhưng tôi không biết cách lấy giá trị thực tế từ đó.

Như mọi khi, cảm ơn sự giúp đỡ của bạn!

+17

Lưu ý rằng đây không phải là mục đích của "động" và kịch bản này không hoạt động tốt hơn với "động" hơn so với "đối tượng". "dynamic" làm cho nó có thể truy cập các thuộc tính khi tên * của thuộc tính được biết tại thời gian biên dịch nhưng * type * thì không. Vì bạn không biết tên cũng như loại tại thời gian biên dịch, năng động sẽ không giúp bạn. –

+0

Có thể có liên quan: http://stackoverflow.com/questions/5877251/lookup-property-in-object-graph-via-a-string. – DuckMaestro

+0

@EricLippert Tôi biết câu hỏi này cũ nhưng chỉ để đưa ra nhận xét trong trường hợp ai đó nhìn thấy nó trong tương lai. Trong một số trường hợp, bạn không thể chọn sử dụng động hay đối tượng (ví dụ khi sử dụng trình phân tích cú pháp JSON) và bạn vẫn có thể muốn lấy các thuộc tính từ một chuỗi (từ tệp cấu hình chẳng hạn). như người ta có thể nghĩ ban đầu. – Pedrom

Trả lời

149

Khi bạn có PropertyInfo (từ GetProperty), bạn cần gọi số GetValue và chuyển vào trường hợp bạn muốn nhận giá trị. Trong trường hợp của bạn:

d.GetType().GetProperty("value2").GetValue(d, null); 
+4

Tôi nhận được một ''d.GetType() GetProperty (" value2 "). GetValue (d)' đã ném ngoại lệ loại 'System.Reflection.TargetInvocationException' \t động {System.Reflection.TargetInvocationException}' trong cửa sổ xem với điều đó ..? – TimDog

+0

@TimDog: Thông báo lỗi trong ngoại lệ là gì? –

+4

Hãy suy nghĩ GetValue cần thông số bổ sung - ví dụ: d.GetType() GetProperty ("value2") GetValue (d, null) – dommer

3

d.GetType().GetProperty("value2")

trả về một đối tượng PropertyInfo.

Vì vậy, sau đó làm

propertyInfo.GetValue(d) 
+0

thanks, đây là câu trả lời đúng, nhưng như đã đề cập ở trên, 'GetValue (d)' cần phải là 'GetValue (d, null)' – TimDog

20

Dynamitey là một mã nguồn mở .net std thư viện, mà cho phép của bạn gọi nó như từ khóa dynamic, nhưng sử dụng một chuỗi cho tên thuộc tính chứ không phải là trình biên dịch làm việc đó cho bạn, và kết thúc là equal to reflection speedwise (không nhanh bằng cách sử dụng từ khóa động, nhưng điều này là do chi phí bổ sung của bộ nhớ đệm động, nơi trình biên dịch lưu trữ tĩnh).

Dynamic.InvokeGet(d,"value2"); 
34
public static object GetProperty(object target, string name) 
{ 
    var site = System.Runtime.CompilerServices.CallSite<Func<System.Runtime.CompilerServices.CallSite, object, object>>.Create(Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, name, target.GetType(), new[]{Microsoft.CSharp.RuntimeBinder.CSharpArgumentInfo.Create(0,null)})); 
    return site.Target(site, target); 
} 

Thêm tham chiếu đến Microsoft.CSharp. Hoạt động cũng cho các loại động và các thuộc tính và trường riêng.

Sửa: Trong khi phương pháp này hoạt động, có gần 20 × nhanh hơn phương pháp từ lắp ráp Microsoft.VisualBasic.dll:

public static object GetProperty(object target, string name) 
{ 
    return Microsoft.VisualBasic.CompilerServices.Versioned.CallByName(target, name, CallType.Get); 
} 
+1

Chỉ muốn đề cập rằng phiên bản VisualBasic không tương đương với phiên bản 'GetProperty' gốc của bạn (GetProperty thực sự gọi GetMember động, hoạt động ngay cả trên các đối tượng Python trong IronPython). – Trevor

+0

Mục tiêu đối tượng sẽ là gì? – Demodave

+0

@Demodave Đối tượng mà bạn muốn gọi thuộc tính ('d' trong câu hỏi). – IllidanS4

7

Phần lớn thời gian khi bạn yêu cầu một đối tượng năng động, bạn nhận được ExpandoObject (không có trong ví dụ ẩn danh nhưng được đánh giá tĩnh của câu hỏi ở trên, nhưng bạn đề cập đến JavaScript và trình phân tích cú pháp JSON đã chọn của tôi JsonFx, cho một, tạo ExpandoObjects).

Nếu động lực của bạn trên thực tế là ExpandoObject, bạn có thể tránh phản ánh bằng cách truyền nó sang IDictionary, như được mô tả tại http://msdn.microsoft.com/en-gb/library/system.dynamic.expandoobject.aspx.

Khi bạn đã đúc để IDictionary, bạn có thể truy cập đến các phương pháp hữu ích như .Item và .ContainsKey

+0

Thật không may, phải chuyển sang IDictionary và sử dụng TryGetValue ví dụ, kết quả trong một đối tượng cũ đơn giản được trả lại. Bạn không thể tận dụng lợi thế của các toán tử ngầm tại thời điểm đó, vì chúng chỉ được xem xét ở thời gian biên dịch. Ví dụ, nếu tôi có một lớp Int64Proxy với chuyển đổi ngầm sang Int64 ?, sau đó là Int64? i = data.value; // dữ liệu là ExpandoObject' sẽ tự động tra cứu và gọi toán tử ngầm. Mặt khác, nếu tôi đã phải sử dụng IDictionary để kiểm tra xem "giá trị" trường tồn tại, tôi muốn có được một đối tượng trở lại mà sẽ không đúc mà không có lỗi để Int64 ?. – Triynko

3

Đây là cách tôi đã nhận được giá trị của một giá trị tài sản của một dinamic:

public dynamic Post(dynamic value) 
    {    
     try 
     { 
      if (value != null) 
      { 
       var valorCampos = ""; 

       foreach (Newtonsoft.Json.Linq.JProperty item in value) 
       { 
        if (item.Name == "valorCampo")//property name 
         valorCampos = item.Value.ToString(); 
       }           

      } 
     } 
     catch (Exception ex) 
     { 

     } 


    } 
5

Phương pháp dễ nhất để có được cả số settergetter đối với thuộc tính hoạt động cho bất kỳ loại nào, bao gồm dynamicExpandoObject là sử dụng FastMember cũng là phương pháp nhanh nhất (sử dụng Emit).

Bạn có thể nhận được TypeAccessor dựa trên một loại nhất định hoặc ObjectAccessor dựa trên phiên bản của một loại nhất định.

Ví dụ:

var staticData = new Test { Id = 1, Name = "France" }; 
var objAccessor = ObjectAccessor.Create(staticData); 
objAccessor["Id"].Should().Be(1); 
objAccessor["Name"].Should().Be("France"); 

var anonymous = new { Id = 2, Name = "Hilton" }; 
objAccessor = ObjectAccessor.Create(anonymous); 
objAccessor["Id"].Should().Be(2); 
objAccessor["Name"].Should().Be("Hilton"); 

dynamic expando = new ExpandoObject(); 
expando.Id = 3; 
expando.Name = "Monica"; 
objAccessor = ObjectAccessor.Create(expando); 
objAccessor["Id"].Should().Be(3); 
objAccessor["Name"].Should().Be("Monica"); 

var typeAccessor = TypeAccessor.Create(staticData.GetType()); 
typeAccessor[staticData, "Id"].Should().Be(1); 
typeAccessor[staticData, "Name"].Should().Be("France"); 

typeAccessor = TypeAccessor.Create(anonymous.GetType()); 
typeAccessor[anonymous, "Id"].Should().Be(2); 
typeAccessor[anonymous, "Name"].Should().Be("Hilton"); 

typeAccessor = TypeAccessor.Create(expando.GetType()); 
((int)typeAccessor[expando, "Id"]).Should().Be(3); 
((string)typeAccessor[expando, "Name"]).Should().Be("Monica"); 
1

Các GetProperty/GetValue không làm việc cho dữ liệu JSON, nó luôn luôn tạo ra một ngoại lệ null, tuy nhiên, bạn có thể thử phương pháp này:

Serialize đối tượng của bạn sử dụng JsonConvert:

var z = Newtonsoft.Json.JsonConvert.DeserializeObject(Convert.ToString(request)); 

sau đó truy cập vào nó trực tiếp đúc nó trở lại chuỗi:

var pn = (string)z["DynamicFieldName"]; 

Nó có thể hoạt động ngay khi áp dụng Convert.ToString (yêu cầu) ["DynamicFieldName"], tuy nhiên tôi chưa thử nghiệm.

+0

Phương pháp này tạo ra lỗi: lỗi CS0021: Không thể áp dụng lập chỉ mục với [] vào biểu thức kiểu 'đối tượng'. Sử dụng 'JavaScriptSerializer mới(). Deserialize (json);' để truy cập "thuộc tính" theo cách bạn đề xuất –

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