Как я отражаю над членами динамического объекта? - PullRequest
122 голосов
/ 14 апреля 2010

Мне нужно получить словарь свойств и их значений из объекта, объявленного с помощью динамического ключевого слова в .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 = ???

Ответы [ 4 ]

97 голосов
/ 14 апреля 2010

В случае ExpandoObject класс ExpandoObject фактически реализует IDictionary<string, object> для своих свойств, поэтому решение так же тривиально, как приведение:

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

Обратите внимание, что это не будет работать для общих динамических объектов. В этих случаях вам нужно будет перейти в DLR через IDynamicMetaObjectProvider.

57 голосов
/ 22 апреля 2010

Есть несколько сценариев для рассмотрения. Прежде всего, вам необходимо проверить тип вашего объекта. Вы можете просто вызвать 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, и игнорировать (или выбросить исключение) для остальных.

30 голосов
/ 26 октября 2011

Если IDynamicMetaObjectProvider может предоставлять имена динамических членов, вы можете получить их. См. Реализацию GetMemberNames в лицензированной Apache библиотеке PCL Dynamitey (которую можно найти в nuget), она работает для ExpandoObject s и DynamicObject s, которые реализуют GetDynamicMemberNames и любые другие IDynamicMetaObjectProvider, которые предоставляют мета-объект с реализацией GetDynamicMemberNames без пользовательского тестирования за пределами is IDynamicMetaObjectProvider.

После того, как вы получили имена членов, немного сложнее найти правильное значение, но Impromptu делает это, но сложнее указать только интересные моменты и сделать так, чтобы это имело смысл. Вот документация , и она равна или быстрее, чем отражение, однако вряд ли она будет быстрее, чем поиск по словарю для expando, но она работает для любого объекта, так называемого expando, динамического или оригинального - назовите его.

16 голосов
/ 23 августа 2016

Требуется 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
}

Выбор получения значения в виде строки или какого-либо другого объекта или создания другой динамики и повторного поиска.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...