Як я відображаю над членами динамічного об'єкта?


131

Мені потрібно отримати словник властивостей та їх значень від об’єкта, декларованого за допомогою динамічного ключового слова в .NET 4? Здається, використовувати роздуми для цього не вийде.

Приклад:

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 = ???

Відповіді:


32

Якщо IDynamicMetaObjectProvider може надати динамічні імена членів, ви можете їх отримати. Дивіться реалізацію GetMemberNames у ліцензованій на апаші ліцензовану бібліотеку PCL Dynamitey (яку можна знайти в nuget), вона працює для ExpandoObjects та DynamicObjects, які реалізують, GetDynamicMemberNamesта будь-який інший, IDynamicMetaObjectProviderякий надає мета-об'єкт з реалізацією GetDynamicMemberNamesбез спеціального тестування за її межами is IDynamicMetaObjectProvider.

Після отримання імен учасників трохи більше роботи, щоб правильно визначити значення, але Impromptu це робить, але важче вказати лише на цікаві біти і мати це має сенс. Ось документація, і вона дорівнює або швидша, ніж відображення, однак, навряд чи буде швидшою, ніж пошук словника для експандо, але він працює для будь-якого об’єкта, експандо, динамічного чи оригінального - ви його називаєте.


17
Завдяки досягненню пункту код: var tTarget = target як IDynamicMetaObjectProvider; if (tTarget! = null) {tList.AddRange (tTarget.GetMetaObject (Expression.Constant (tTarget)). GetDynamicMemberNames ()); }
Flatliner DOA

дякую за велику бібліотеку У мене виникли проблеми з круглим відключенням динамічного об’єкта в цій бібліотеці dinamijson.codeplex.com , і я зміг розширити його разом із вашою бібліотекою.
JJS

1
Приклад, будь ласка.
Демодав

105

У випадку ExpandoObject клас ExpandoObject реально реалізує IDictionary<string, object>для своїх властивостей, тому рішення є таким же тривіальним, як і кастинг:

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

Зауважте, що це не буде працювати для загальних динамічних об'єктів. У цих випадках вам потрібно буде перейти до DLR через IDynamicMetaObjectProvider.


Дякую за це, на жаль, зразок трохи спрощений. Мені потрібно вміти оглянути динамічний об’єкт, не знаючи, що це за реальний тип.
Flatliner DOA

2
Це працює лише для об’єктів класу ExpandoObject, клас DynamicObject - це ще один розширюваний клас, який не реалізує IDictionary, а реалізує IDynamicMetaObjectProvider.
Шарік Абдулла

1
Однак це відповідає на питання ОП.
Шарік Абдулла

58

Існує кілька сценаріїв, які слід враховувати. Перш за все, вам потрібно перевірити тип вашого об’єкта. Ви можете просто зателефонувати GetType () для цього. Якщо тип не реалізує IDynamicMetaObjectProvider, то ви можете використовувати відображення так само, як і для будь-якого іншого об'єкта. Щось на зразок:

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

Однак для реалізацій IDynamicMetaObjectProvider просте відображення не працює. В основному вам потрібно більше знати про цей об’єкт. Якщо це ExpandoObject (який є однією з реалізацій IDynamicMetaObjectProvider), ви можете використовувати відповідь, надану itowlson. ExpandoObject зберігає його властивості у словнику, і ви можете просто віддати динамічний об’єкт до словника.

Якщо це DynamicObject (інша реалізація IDynamicMetaObjectProvider), то вам потрібно використовувати будь-які методи, які цей DynamicObject піддається. DynamicObject не потрібно "зберігати" свій список властивостей у будь-якому місці. Наприклад, це може зробити щось подібне (я повторно використовую приклад із своєї публікації в блозі ):

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

У цьому випадку, коли ви намагаєтеся отримати доступ до властивості (з будь-яким даним іменем), об'єкт просто повертає ім'я властивості у вигляді рядка.

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

Отже, у вас немає нічого над цим відображати - цей об’єкт не має ніяких властивостей, і в той же час всі дійсні імена властивостей будуть працювати.

Я б сказав, що для реалізацій IDynamicMetaObjectProvider вам потрібно відфільтрувати відомі реалізації, де ви можете отримати список властивостей, таких як ExpandoObject, і проігнорувати (або викинути виняток) для решти.


7
Мені просто здається, що якщо тип, який я споживаю, є динамічним, то я не повинен робити припущення про його базовий тип. Я повинен мати можливість зателефонувати на GetDynamicMemberNames, щоб отримати список членів. Здається дурним, що статичні типи мають кращу підтримку перевірки виконання, ніж динамічні!
Flatliner DOA

2
Ви можете змінити метод GetDynamicMemberNames () для динамічного об'єкта, щоб повернути імена списку динамічних членів. Проблема полягає в тому, що не гарантується, що кожен динамічний об'єкт має цей метод (ExpandoObject не має). Не дивно, що відображення працює краще для статичних типів. Він створений для них в першу чергу. З динамікою ви повинні більше покладатися на тестування одиниць та TDD.
Олександра Русіна

1
Документація MSDN для GetDynamicMemberNames () згадує: "Цей метод існує лише для налагодження.", Не дуже втішний :(
NicoJuicy

19

Потрібен Newtonsoft Json.Net

Трохи пізно, але я придумав це. Він дає вам лише клавіші, а потім ви можете використовувати ті, що в динаміці:

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;
}

Тоді ви просто пророкуєте так:

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

Вибираючи, щоб отримати значення у вигляді рядка або якогось іншого об'єкта, або зробіть іншу динаміку та знову використовуйте пошук.


Вам не потрібен список для повернення.
aloisdg переходить на codidact.com

4
Ідеально! Мені довелося змінити атрибути JObjectAsJObject = dynamicToGetPropertiesFor; до Object attributesAsJObject = (JObject) JToken.FromObject (obj); хоча !!
k25

Просто щоб повторити те, що сказав @ k25. Ви повинні замінити JObject attributesAsJObject = dynamicToGetPropertiesFor;що - щось на кшталт: var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);. У цей момент ви можете отримати словник імен властивостей і значень, зробивши щось подібне var objProperties = jObject.ToObject<Dictionary<string, object>>();. Із цим у руці ви їдете на перегони. Для цього не потрібна динаміка. Він добре працює з усім, що є підкласомDynamicObject
Flydog57,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.