Làm thế nào để tôi phản ánh qua các thành viên của đối tượng năng động?


131

Tôi cần lấy một từ điển các thuộc tính và các giá trị của chúng từ một đối tượng được khai báo bằng từ khóa động trong .NET 4? Có vẻ như sử dụng sự phản chiếu cho điều này sẽ không hoạt động.

Thí dụ:

dynamic s = new ExpandoObject();
s.Path = "/Home";
s.Name = "Home";

// How do I enumerate the Path and Name properties and get their values?
IDictionary<string, object> propertyValues = ???

Câu trả lời:


32

Nếu ID ẩnMetaObjectProvider có thể cung cấp tên thành viên động, bạn có thể lấy chúng. Xem GetMemberNames thực hiện trong apache phép thư viện PCL Dynamitey (có thể được tìm thấy trong NuGet), nó hoạt động cho ExpandoObjects và DynamicObjects mà thực hiện GetDynamicMemberNamesvà bất kỳ khác IDynamicMetaObjectProviderngười cung cấp một đối tượng meta với một thực hiện GetDynamicMemberNamesmà không cần kiểm tra tùy chỉnh ngoài is IDynamicMetaObjectProvider.

Sau khi nhận được tên thành viên, công việc của bạn sẽ có thêm một chút công việc để có được giá trị đúng cách, nhưng Impromptu làm điều này nhưng thật khó để chỉ ra các bit thú vị và có ý nghĩa. Đây là tài liệu và nó bằng hoặc nhanh hơn phản chiếu, tuy nhiên, không thể nhanh hơn tra cứu từ điển để mở rộng, nhưng nó hoạt động cho mọi đối tượng, mở rộng, động hoặc nguyên bản - bạn đặt tên cho nó.


17
Nhờ vào điểm mà mã là: var tTarget = target dưới dạng IDAVEMetaObjectProvider; if (tTarget! = null) {tList.AddRange (tTarget.GetMetaObject (Expression.Constant (tTarget)). GetDocateMemberNames ()); }
phẳng DOA

cảm ơn thư viện tuyệt vời của bạn Tôi đã gặp sự cố khi vấp một đối tượng động đối với thư viện này Dynamicjson.codeplex.com và đã có thể mở rộng nó với thư viện của bạn.
JJS

1
làm ơn ví dụ
Giải trừ

105

Trong trường hợp ExpandoObject, lớp ExpandoObject thực sự triển khai IDictionary<string, object>cho các thuộc tính của nó, vì vậy giải pháp này không quan trọng bằng việc truyền:

IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;

Lưu ý rằng điều này sẽ không hoạt động cho các đối tượng động nói chung. Trong những trường hợp này, bạn sẽ cần phải thả xuống DLR thông qua IDAVEMetaObjectProvider.


Cảm ơn vì điều đó, không may là mẫu hơi quá đơn giản. Tôi cần có khả năng kiểm tra một vật thể động mà không cần biết loại thực sự của nó là gì.
phẳng DOA

2
Điều này chỉ hoạt động cho các đối tượng của lớp ExpandoObject, lớp DynamicObject là một lớp có thể mở rộng khác không triển khai IDadata mà chỉ thực hiện ID ẩnMetaObjectProvider.
Sharique Abdullah

1
Nó trả lời câu hỏi của OP.
Sharique Abdullah

58

Có một số kịch bản để xem xét. Trước hết, bạn cần kiểm tra loại đối tượng của bạn. Bạn chỉ cần gọi GetType () cho việc này. Nếu loại không triển khai ID ẩnMetaObjectProvider, thì bạn có thể sử dụng sự phản chiếu giống như đối với bất kỳ đối tượng nào khác. Cái gì đó như:

var propertyInfo = test.GetType().GetProperties();

Tuy nhiên, đối với các triển khai ID ẩnMetaObjectProvider, sự phản chiếu đơn giản không hoạt động. Về cơ bản, bạn cần biết thêm về đối tượng này. Nếu đó là ExpandoObject (là một trong những triển khai ID ẩnMetaObjectProvider), bạn có thể sử dụng câu trả lời được cung cấp bởi itowlson. ExpandoObject lưu trữ các thuộc tính của nó trong một từ điển và bạn có thể chỉ cần truyền đối tượng động của mình vào một từ điển.

Nếu đó là DynamicObject (một triển khai ID ẩnMetaObjectProvider khác), thì bạn cần sử dụng bất kỳ phương thức nào mà DynamicObject này trưng ra. DynamicObject không bắt buộc phải thực sự "lưu trữ" danh sách các thuộc tính của nó ở bất cứ đâu. Ví dụ: nó có thể làm một cái gì đó như thế này (tôi đang sử dụng một ví dụ từ bài đăng trên blog của tôi ):

public class SampleObject : DynamicObject
{
    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        result = binder.Name;
        return true;
    }
}

Trong trường hợp này, bất cứ khi nào bạn cố gắng truy cập vào một thuộc tính (với bất kỳ tên đã cho nào), đối tượng chỉ cần trả về tên của thuộc tính dưới dạng một chuỗi.

dynamic obj = new SampleObject();
Console.WriteLine(obj.SampleProperty);
//Prints "SampleProperty".

Vì vậy, bạn không có bất cứ điều gì để phản ánh - đối tượng này không có bất kỳ thuộc tính nào, đồng thời tất cả các tên thuộc tính hợp lệ sẽ hoạt động.

Tôi muốn nói về việc triển khai ID ẩnMetaObjectProvider, bạn cần lọc các triển khai đã biết nơi bạn có thể nhận danh sách các thuộc tính, chẳng hạn như ExpandoObject và bỏ qua (hoặc ném ngoại lệ) cho phần còn lại.


7
Dường như với tôi rằng nếu loại tôi tiêu thụ là Động thì tôi không nên đưa ra giả định về loại cơ bản. Tôi có thể gọi GetD bitMemberNames để nhận danh sách thành viên. Có vẻ ngu ngốc khi các loại tĩnh có hỗ trợ kiểm tra thời gian chạy tốt hơn các loại động!
phẳng DOA

2
Bạn có thể ghi đè phương thức GetD bitMemberNames () cho một đối tượng động để trả về tên danh sách của các thành viên động. Vấn đề là không đảm bảo rằng mọi đối tượng động đều có phương thức này (ExpandoObject không). Không có gì đáng ngạc nhiên khi sự phản chiếu hoạt động tốt hơn cho các loại tĩnh. Nó được tạo ra cho họ ở nơi đầu tiên. Với tính năng động, bạn phải phụ thuộc nhiều hơn vào kiểm tra đơn vị và TDD.
Alexandra Rusina

1
Tài liệu MSDN cho GetD bitMemberNames () đề cập: "Phương pháp này chỉ tồn tại cho mục đích gỡ lỗi.", Không thực sự an ủi :(
NicoJuicy

19

Yêu cầu Newtonsoft Json.Net

Một chút muộn, nhưng tôi đã đưa ra điều này. Nó chỉ cung cấp cho bạn các phím và sau đó bạn có thể sử dụng các phím đó trên động:

public List<string> GetPropertyKeysForDynamic(dynamic dynamicToGetPropertiesFor)
{
    JObject attributesAsJObject = dynamicToGetPropertiesFor;
    Dictionary<string, object> values = attributesAsJObject.ToObject<Dictionary<string, object>>();
    List<string> toReturn = new List<string>();
    foreach (string key in values.Keys)
    {
        toReturn.Add(key);                
    }
    return toReturn;
}

Sau đó, bạn chỉ cần thuyết minh như thế này:

foreach(string propertyName in GetPropertyKeysForDynamic(dynamicToGetPropertiesFor))
{
    dynamic/object/string propertyValue = dynamicToGetPropertiesFor[propertyName];
    // And
    dynamicToGetPropertiesFor[propertyName] = "Your Value"; // Or an object value
}

Chọn lấy giá trị dưới dạng chuỗi hoặc một số đối tượng khác hoặc thực hiện một động khác và sử dụng lại tra cứu.


Bạn không cần danh sách để quay trở lại.
aloisdg chuyển đến codidact.com

4
Hoàn hảo! Tôi đã phải thay đổi các thuộc tính JObjectAsJObject = DynamicToGetProperIESFor; đối tượng thuộc tínhAsJObject = (JObject) JToken.FromObject (obj); Tuy nhiên!!
k25

Chỉ cần nhắc lại những gì @ k25 đã nói. Bạn cần thay thế JObject attributesAsJObject = dynamicToGetPropertiesFor;bằng một cái gì đó như : var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);. Tại thời điểm đó, bạn có thể nhận được một từ điển các tên và giá trị thuộc tính bằng cách thực hiện một cái gì đó như var objProperties = jObject.ToObject<Dictionary<string, object>>();. Với điều đó trong tay, bạn đi đến các chủng tộc. Điều này không cần một động lực. Nó hoạt động tốt với bất cứ thứ gì thuộc lớp con củaDynamicObject
Flydog57
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.