Как я могу отражать элементы динамического объекта?
Мне нужно получить словарь свойств и их значений из объекта, объявленного с помощью ключевого слова dynamic в .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 = ???
Ответы
Ответ 1
Если IDynamicMetaObjectProvider может предоставить имена динамических членов, вы можете их получить. См. GetMemberNames в библиотеке PCL с лицензией apache Dynamitey (которую можно найти в nuget), это работает для ExpandoObject
и DynamicObject
, которые реализуют GetDynamicMemberNames
и любые другие IDynamicMetaObjectProvider
, которые предоставляют метаобъект с реализацией GetDynamicMemberNames
без специального тестирования за пределами is IDynamicMetaObjectProvider
.
После получения имен членов это немного больше, чтобы получить правильное значение, но Impromptu делает это, но сложнее указать только на интересные биты и иметь смысл. Здесь документация и она равна или быстрее, чем отражение, однако вряд ли будет быстрее, чем поиск словаря для expando, но он работает для любого объекта, expando, dynamic или оригинал - вы называете его.
Ответ 2
В случае ExpandoObject класс ExpandoObject фактически реализует IDictionary<string, object>
для своих свойств, поэтому решение так же тривиально, как и кастинг:
IDictionary<string, object> propertyValues = (IDictionary<string, object>)s;
Обратите внимание, что это не будет работать для общих динамических объектов. В этих случаях вам нужно будет спуститься к DLR через IDynamicMetaObjectProvider.
Ответ 3
Существует несколько сценариев.
Прежде всего, вам нужно проверить тип вашего объекта. Вы можете просто вызвать 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, и игнорировать (или исключать исключение) для остальных.
Ответ 4
Требуется 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
}
Выбор значения в виде строки или какого-либо другого объекта или другого динамика и повторного поиска.