8

Tôi đang tìm cách thêm thành viên tự động vào đối tượng động. OK, tôi đoán một chút làm rõ là cần thiết ...Tự động thêm thành viên vào đối tượng động

Khi bạn làm điều đó:

dynamic foo = new ExpandoObject(); 
foo.Bar = 42; 

Thuộc tính Bar sẽ được thêm tự động khi chạy. Nhưng mã vẫn đề cập đến "tĩnh" tới Bar (tên "Bar" được mã hóa cứng) ... Nếu tôi muốn thêm thuộc tính vào thời gian chạy mà không biết tên của nó tại thời gian biên dịch thì sao?

tôi biết làm thế nào để làm điều này với một đối tượng tùy chỉnh năng động (Tôi thực sự blogged about it một vài tháng trước), sử dụng các phương pháp của lớp DynamicObject, nhưng làm thế nào tôi có thể làm điều đó với bất kỳ đối tượng động?

Tôi có thể sử dụng giao diện IDynamicMetaObjectProvider, nhưng tôi không hiểu cách sử dụng nó. Ví dụ, đối số nào tôi nên chuyển sang phương thức GetMetaObject? (nó mong đợi một Expression)

Và bằng cách này, làm thế nào để bạn thực hiện sự phản chiếu trên các đối tượng động? Phản xạ "thông thường" và TypeDescriptor không hiển thị thành viên năng động ...

Mọi thông tin chi tiết sẽ được đánh giá cao!

+0

Trong C# 6.0, * có thể là * bạn có thể viết nó như 'foo. $ Bar = 42;' :) Không chắc chắn nó có được phép ... – nawfal

+0

@nawfal, thực sự, tính năng đó đã bị xóa. Nhưng dù sao, 'foo. $ Bar' chỉ là viết tắt của' foo ["Bar"] ' –

+0

Thomas, không biết về tính năng bị bỏ (tôi rất vui vì nó), nhưng ồ phải, trong một khoảnh khắc Tôi đã bỏ qua yêu cầu thực sự của q của bạn. – nawfal

Trả lời

9

Điều bạn muốn tương tự với hàm getattr/setattr của Python. Không có cách nào tương đương được xây dựng trong C# hoặc VB.NET. Lớp ngoài của DLR (mà tàu w/IronPython và IronRuby trong Microsoft.Scripting.dll) bao gồm một bộ các API lưu trữ bao gồm một API ObjectOperations có các phương thức GetMember/SetMember. Bạn có thể sử dụng chúng nhưng bạn cần thêm sự phụ thuộc của DLR và ngôn ngữ dựa trên DLR.

Có lẽ cách tiếp cận đơn giản nhất là tạo một CallSite w/một trong các trình kết dính C# hiện có. Bạn có thể lấy mã cho điều này bằng cách xem kết quả của "foo.Bar = 42" trong ildasm hoặc phản xạ. Tuy nhiên, một ví dụ đơn giản này sẽ là:

object x = new ExpandoObject(); 
CallSite<Func<CallSite, object, object, object>> site = CallSite<Func<CallSite, object, object, object>>.Create(
      Binder.SetMember(
       Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags.None, 
       "Foo", 
       null, 
       new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) } 
      ) 
     ); 
site.Target(site, x, 42); 
Console.WriteLine(((dynamic)x).Foo); 
+0

Tôi cần phải mất một thời gian để chắc chắn rằng tôi thực sự hiểu những gì mã này đang làm, nhưng dù sao nó làm việc tốt ... Cảm ơn! –

+0

Có thể thực hiện điều này <.Net 4.0 bằng DLR không? Dường như việc sử dụng năng động sẽ loại trừ điều này. – Firestrand

+0

Phương pháp trên không nên hoạt động bình thường. Trang web cuộc gọi Setter yêu cầu 2 thông tin đối số được cung cấp thay vì 1. Định nghĩa chính xác sẽ là: new [] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null) } –

5

Các mã nguồn mở khuôn khổ Dynamitey sẽ làm điều này (có sẵn thông qua nuget). Nó đóng gói trong khi vẫn còn bộ nhớ đệm trang web cuộc gọi và mã chất kết dính mà @ Dino-Viehland sử dụng.

Dynamic.InvokeSet(foo,"Bar",42); 

Nó cũng có thể gọi nhiều other kinds of c# binder too.

5

ExpandoObject triển khai IDictionary < chuỗi, đối tượng > mặc dù rõ ràng. Điều này có nghĩa là bạn chỉ có thể truyền ExpandoObject thành chuỗi IDictionary <, đối tượng > và thao tác từ điển.

dynamic foo = new ExpandoObject(); 
foo.Bar = 42; 
food = (IDictionary<string,object>)foo; 
food["Baz"] = 54 
+0

Cảm ơn! Thật vậy ExpandoObject thực hiện IDictionary, như tôi nhận ra sau đó, vì vậy nó rõ ràng là giải pháp đơn giản nhất trong trường hợp đó. Tuy nhiên phạm vi của câu hỏi của tôi là rộng hơn: Tôi đã tìm kiếm một giải pháp mà sẽ làm việc với bất kỳ đối tượng năng động, không chỉ ExpandoObject –

1

Tôi biết điều này là khá một bài cũ, nhưng tôi nghĩ rằng tôi muốn vượt qua cùng Miron Abramson solution về cách bạn có thể tạo kiểu riêng của bạn và thêm các thuộc tính trong thời gian chạy - trong trường hợp bất cứ ai khác ngoài kia đang tìm kiếm một cái gì đó giống.

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