Jak zastanowić się nad elementami dynamicznego obiektu?


132

Muszę uzyskać słownik właściwości i ich wartości z obiektu zadeklarowanego za pomocą dynamicznego słowa kluczowego w .NET 4? Wydaje się, że użycie 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 = ???

Odpowiedzi:


32

Jeśli IDynamicMetaObjectProvider może dostarczyć dynamiczne nazwy członków, możesz je pobrać. Zobacz GetMemberNames wdrożenie w Apache License biblioteki PCL Dynamitey (które można znaleźć w Nuget), to działa na ExpandoObjectS i DynamicObjectS, która wdrożenia GetDynamicMemberNamesi każdy inny IDynamicMetaObjectProvider, który stanowi przedmiot meta z realizacji GetDynamicMemberNamesbez zwyczaj badania spoza is IDynamicMetaObjectProvider.

Po uzyskaniu nazw członków potrzeba trochę więcej pracy, aby uzyskać odpowiednią wartość, ale Impromptu to robi, ale trudniej jest wskazać tylko interesujące fragmenty i mieć sens. Oto dokumentacja i jest równa lub szybsza niż odbicie, jednak jest mało prawdopodobne, aby była szybsza niż wyszukiwanie w słowniku dla expando, ale działa dla dowolnego obiektu, expando, dynamicznego lub oryginalnego - nadasz mu nazwę.


17
Dzięki temu kod jest następujący: var tTarget = target as IDynamicMetaObjectProvider; if (tTarget! = null) {tList.AddRange (tTarget.GetMetaObject (Expression.Constant (tTarget)). GetDynamicMemberNames ()); }
Flatliner DOA

dzięki za wspaniałą bibliotekę. Miałem problemy z przekierowaniem dynamicznego obiektu do tej biblioteki dynamicjson.codeplex.com i mogłem go rozszerzyć o twoją bibliotekę.
JJS

1
przykład proszę.
Demodave,

105

W przypadku ExpandoObject klasa ExpandoObject faktycznie implementuje IDictionary<string, object>swoje właściwości, więc rozwiązanie jest tak banalne jak rzutowanie:

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

Zauważ, że to nie zadziała dla ogólnych obiektów dynamicznych. W takich przypadkach musisz przejść do DLR za pośrednictwem IDynamicMetaObjectProvider.


Dzięki za to, niestety próbka została trochę uproszczona. Muszę mieć możliwość zbadania dynamicznego obiektu, nie wiedząc, jaki jest jego prawdziwy typ.
Flatliner DOA

2
Działa to tylko dla obiektów klasy ExpandoObject, klasa DynamicObject jest kolejną rozszerzalną klasą, która nie implementuje IDictionary, ale raczej implementuje IDynamicMetaObjectProvider.
Sharique Abdullah

1
Odpowiada jednak na pytanie PO.
Sharique Abdullah

58

Należy wziąć pod uwagę kilka scenariuszy. Przede wszystkim musisz sprawdzić typ swojego obiektu. W tym celu możesz po prostu wywołać GetType (). Jeśli typ nie implementuje IDynamicMetaObjectProvider, możesz użyć odbicia takiego samego, jak w przypadku każdego innego obiektu. Coś jak:

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

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

Jeśli jest to DynamicObject (inna implementacja IDynamicMetaObjectProvider), musisz użyć wszelkich metod, które ujawnia ten DynamicObject. DynamicObject nie musi faktycznie „przechowywać” swojej listy właściwości w dowolnym miejscu. Na przykład może zrobić coś takiego (ponownie używam przykładu 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 spróbujesz uzyskać dostęp do właściwości (o dowolnej nazwie), obiekt po prostu zwraca nazwę właściwości jako ciąg.

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

Nie masz więc nad czym się zastanawiać - ten obiekt nie ma żadnych właściwości, a jednocześnie wszystkie prawidłowe nazwy właściwości będą działać.

Powiedziałbym, że w przypadku implementacji IDynamicMetaObjectProvider musisz przefiltrować znane implementacje, w których możesz uzyskać listę właściwości, takich jak ExpandoObject, i zignorować (lub wyrzucić wyjątek) dla reszty.


7
Po prostu wydaje mi się, że jeśli typ, który konsumuję, jest typem dynamicznym, to nie powinienem robić założeń na temat jego podstawowego typu. Powinienem być w stanie zadzwonić do GetDynamicMemberNames, aby uzyskać listę członków. Wydaje się głupie, że typy statyczne mają lepszą obsługę inspekcji w czasie wykonywania niż typy dynamiczne!
Flatliner DOA

2
Można przesłonić metodę GetDynamicMemberNames (), aby obiekt dynamiczny zwracał nazwy list członków dynamicznych. Problem polega na tym, że nie ma gwarancji, że każdy obiekt dynamiczny ma tę metodę (ExpandoObject nie). Nic dziwnego, że odbicie działa lepiej w przypadku typów statycznych. Został stworzony dla nich przede wszystkim. W przypadku dynamiki musisz bardziej polegać na testach jednostkowych i TDD.
Alexandra Rusina

1
Dokumentacja MSDN dla GetDynamicMemberNames () wspomina: „Ta metoda istnieje tylko do celów debugowania.”,
Niezbyt

19

Wymaga Newtonsoft Json.Net

Trochę późno, ale wpadłem na to. Daje ci tylko klucze, a następnie możesz 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;
}

Wtedy po prostu zawsze tak:

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

Decydując się na pobranie wartości w postaci ciągu znaków lub innego obiektu lub wykonanie innej dynamiki i ponowne użycie wyszukiwania.


Nie potrzebujesz listy do zwrotu.
aloisdg przenosi się na codidact.com

4
Idealny! Musiałem zmienić atrybuty JObjectAsJObject = dynamicToGetPropertiesFor; to Object attributeAsJObject = (JObject) JToken.FromObject (obj); chociaż!!
k25

Powtarzam tylko to, co powiedział @ k25. Trzeba wymienić JObject attributesAsJObject = dynamicToGetPropertiesFor;coś jak: var jObject = (JObject) JToken.FromObject(dynamicToGetPropertiesFor);. W tym momencie możesz uzyskać słownik nazw właściwości i wartości, wykonując coś podobnego var objProperties = jObject.ToObject<Dictionary<string, object>>();. Mając to na uwadze, ruszasz na wyścigi. To nie wymaga dynamiki. Działa dobrze ze wszystkim, co jest podklasąDynamicObject
Flydog57
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.