2009-12-18 40 views
8

Có, tiêu đề có vẻ hơi khó hiểu, vì vậy tôi sẽ giải thích ý tôi là: giả sử bạn có đối tượng C# 4.0 'động' và tên của thuộc tính. Làm thế nào bạn sẽ lấy tài sản đó từ đối tượng động?Nhận giá trị từ một đối tượng động động

Nói cách khác, làm thế nào bạn sẽ thực hiện:

public static object GetDynamicValue(dynamic o, string name) { ... } 

Một cách khác để đặt nó là tôi đang cố gắng để đối xử với một đối tượng động như một IDictionary. Lưu ý rằng phản chiếu có thể không phải là một tùy chọn ở đây, vì đối tượng động có thể là triển khai tùy chỉnh không dựa trên phản chiếu (ví dụ: bằng cách mở rộng DynamicObject và thực hiện điều riêng của nó).

+1

Bạn có thể nói rõ hơn một chút về trường hợp sử dụng của bạn? Nếu bạn muốn có một đối tượng động tương tự như IDictionary, tại sao không sử dụng ExpandoObject, chẳng hạn? Đề xuất của Jon có thể hoạt động, nhưng tôi có cảm giác rằng đây là một giải pháp quá phức tạp cho những gì bạn đang cố gắng làm. –

Trả lời

13

Bạn sẽ phải xây dựng một trang web gọi, tạo ra một chất kết dính, vv

Cách đơn giản nhất để xem những gì xảy ra là để biên dịch này:

public static object GetDynamicValue(dynamic o, string name) 
{ 
    return o.Foo; 
} 

Sau đó dịch ngược nó với Reflector và làm việc ra những gì nó đang làm. Nó sẽ khá phức tạp, nhớ bạn - và bạn sẽ cần phải thay đổi nó từ một trang web gọi duy nhất, tĩnh, được lưu trữ để tạo một trang mới trên mỗi lời gọi.

Dưới đây là một ví dụ mà không làm việc ... nhưng cho dù đó là hoàn toàn đúng hay không là một vấn đề khác nhau :) (Tôi đã đi này bằng cách thực hiện chính xác những gì tôi đã gợi ý ở trên.)

using Microsoft.CSharp.RuntimeBinder; 
using System; 
using System.Dynamic; 
using System.Runtime.CompilerServices; 

class Test 
{ 
    public static object GetDynamicValue(dynamic o, string name) 
    { 
     CallSite<Func<CallSite, object, object>> site 
      = CallSite<Func<CallSite, object, object>>.Create 
      (Binder.GetMember(CSharpBinderFlags.None, name, 
      typeof(Test), new CSharpArgumentInfo[] 
      { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })); 
     return site.Target(site, o); 
    } 

    static void Main() 
    { 
     Console.WriteLine(GetDynamicValue("hello", "Length")); 
    } 
} 
+0

Rất đẹp, cảm ơn Jon! Điều đó mang lại rất nhiều khái niệm mà tôi chưa xử lý, vì vậy tôi sẽ cần nghiên cứu cẩn thận. Nó cảm thấy lạ rằng typeof (Test) được sử dụng trong đó, vì nó không có liên quan. Nhưng tôi đã thử thiết lập nó thành null và mã vẫn hoạt động, vì vậy dường như nó không hoạt động nhiều. –

+3

Nó có liên quan về những gì các thành viên có thể truy cập - bạn sẽ có thể nhận được ở các thành viên riêng của Test bằng cách sử dụng mã này, nhưng không phải là thành viên riêng tư của các loại khác. –

3

Các Khung nguồn mở ImpromptuInterface (có sẵn trong nuget) thực hiện điều này, và thực hiện công việc phụ có liên quan vì bộ nhớ đệm trang web cuộc gọi là quan trọng đối với hiệu suất.

Xem InvokeGet

public static object GetDynamicValue(dynamic o, string name) { 
     return Impromptu.InvokeGet(o,name); 
} 
+0

Đất sét cũng giống như vậy (http://clay.codeplex.com/) –

+0

@ David-Ebbo Trong khi Clay cho phép bạn truy cập các thuộc tính riêng của nó thông qua tên chuỗi, 'InvokeGet' cho phép bạn truy cập bất kỳ thuộc tính IDYMicOetaObjectProvider thông qua tên chuỗi (hoặc bất kỳ đối tượng thường xuyên nào phản chiếu nhanh hơn) ... trừ khi tôi thiếu một cái gì đó. – jbtule

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