Jak odbić elementy obiektu dynamicznego?

Muszę uzyskać słownik właściwości i ich wartości z obiektu zadeklarowanego za pomocą słowa kluczowego dynamic w. Net 4? Wydaje się, że używanie do tego refleksji nie zadziała.

Przykład:

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 = ???
Author: abatishchev, 2010-04-14

4 answers

Jeśli IDynamicMetaObjectProvider może podać dynamiczne nazwy członków, możesz je pobrać. Zobacz implementację GetMemberNames w Apache licensed PCL library Dynamitey (którą można znaleźć w nuget), działa ona dla ExpandoObjects I DynamicObjects, które implementują GetDynamicMemberNames oraz dla każdego innego IDynamicMetaObjectProvider, który dostarcza meta obiekt z implementacją GetDynamicMemberNames bez niestandardowych testów poza is IDynamicMetaObjectProvider.

Po uzyskaniu nazw członków jest trochę więcej pracy, aby uzyskać wartość we właściwy sposób, ale Impromptu robi to, ale trudniej wskazać tylko interesujące fragmenty i mieć to sens. Poniżej znajduje się dokumentacja i jest równa lub szybsza od reflection, jednak raczej nie będzie szybsza niż wyszukiwanie słownikowe dla expando, ale działa dla dowolnego obiektu, expando, dynamicznego lub oryginalnego - nazwij go.

 28
Author: jbtule,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-07 13:31:33

W przypadku ExpandoObject, Klasa ExpandoObject faktycznie implementuje IDictionary<string, object> dla swoich właściwości, więc rozwiązanie jest równie trywialne jak casting:

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

Zauważ, że to nie będzie działać dla ogólnych obiektów dynamicznych. W takich przypadkach należy przejść do DLR za pomocą IDynamicMetaObjectProvider.

 92
Author: itowlson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-14 04:49:07

Istnieje kilka scenariuszy do rozważenia. Przede wszystkim musisz sprawdzić typ swojego obiektu. Możesz po prostu wywołać GetType () w tym celu. Jeżeli Typ nie implementuje IDynamicMetaObjectProvider, wtedy można użyć reflection tak samo jak dla każdego innego obiektu. Coś w stylu:

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

Jednak w przypadku implementacji IDynamicMetaObjectProvider proste odbicie nie działa. Zasadniczo musisz wiedzieć więcej o tym obiekcie. Jeśli jest to ExpandoObject (który jest jednym z Implementacje IDynamicMetaObjectProvider), możesz skorzystać z odpowiedzi dostarczonej przez itowlson. ExpandoObject przechowuje swoje właściwości w Słowniku i możesz po prostu oddać swój dynamiczny obiekt do słownika.

Jeśli jest to DynamicObject( Inna implementacja IDynamicMetaObjectProvider), to musisz użyć dowolnych metod, które wyświetli ten DynamicObject. DynamicObject nie jest wymagany do "przechowywania" jego listy właściwości w dowolnym miejscu. Na przykład, może zrobić coś takiego (używam ponownie przykład z mojego posta na blogu):

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

W tym przypadku, za każdym razem, gdy próbujesz uzyskać dostęp do właściwości (o dowolnej nazwie), obiekt zwraca po prostu nazwę właściwości jako łańcuch znaków.

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

Więc nie masz nic do odzwierciedlenia - ten obiekt nie ma żadnych właściwości, a jednocześnie wszystkie poprawne nazwy właściwości będą działać.

Powiedziałbym, że dla implementacji IDynamicMetaObjectProvider, trzeba filtrować na znanych implementacjach, gdzie można uzyskać listę właściwości, takie jak ExpandoObject i Ignoruj (lub wyrzuć wyjątek) dla reszty.

 56
Author: Alexandra Rusina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-10 14:02:14

Wymaga Newtonsoft Json.Net

Trochę późno, ale wymyśliłem to. Daje tylko klucze, a następnie można użyć tych na dynamice:
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;
}

Następnie po prostu foreach Tak:

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

Wybór, aby uzyskać wartość jako ciąg znaków lub jakiś inny obiekt, lub wykonać inną dynamikę i ponownie użyć odnośnika.

 12
Author: Mr. B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-28 20:39:45