2011-12-25 9 views
54

Załóżmy, że mam dynamiczną zmienną (odbicie):Get wartości właściwości z C# dynamicznego obiektu przez ciąg

dynamic d = *something* 

Teraz coś tworzy właściwości d którą mam z drugiej strony z ciągiem array:

string[] strarray = { 'property1','property2',..... } 

Nie znam nazwy nieruchomości z góry.

Jak w kodzie, po utworzeniu d i wyciągnięciu strarray z DB, mogę uzyskać wartości?

Chcę uzyskać d.property1 , d.property2.

Widzę, że obiekt ma wewnętrzny słownik _dictionary, który zawiera klucze i wartości, jak je odzyskać?

+1

Czy 'coś' jest' IDynamicMetaObjectProvider'? – SLaks

+0

Sprawdź typ środowiska wykonawczego 'coś' w debugerze i spójrz na jego publicznych członków. – SLaks

+1

Czy możesz sprawdzić, co daje 'd.GetType()' w czasie wykonywania? –

Odpowiedz

77

ja nie wiem, czy istnieje bardziej elegancki sposób z dynamicznie tworzonych obiektów, ale stosując zwykły stary odbicie powinno działać:

var nameOfProperty = "property1"; 
var propertyInfo = myObject.GetType().GetProperty(nameOfProperty); 
var value = propertyInfo.GetValue(myObject, null); 

GetProperty powróci null czy typ myObject nie zawiera własność publiczną z tą nazwą.


EDIT: Jeśli obiekt nie jest „normalne”, ale coś przedmiot wykonawczych IDynamicMetaObjectProvider podejście to nie będzie działać. Proszę spojrzeć na to pytanie zamiast:

+0

Niestety nie działa: object obj = serializer.Deserialize(json, typeof(object)); var propertyInfo = obj.GetType().GetProperty("H3"); var value = propertyInfo.GetValue(obj, null); PropertyInfo jest zero, 3. linia zgłasza wyjątek . –

+0

@ sergata.NETLTD: Ale 'var value = obj.H3' będzie działać? Czy możesz to sprawdzić? – Heinzi

+0

tak, to by działało. Działa to: dynamic obj = serializer.Deserialize (json, typeof (object)); var value = obj.H3; wartość zawiera odpowiednią wartość. Problem polega na tym, że nie wiem, czy H3 to nazwa nieruchomości z góry. Nazwy właściwości pochodzą z DB. Dzięki za pomoc. –

17

To daje wszystkie nazwy właściwości i wartości określone w zmiennej dynamicznej.

dynamic d = { // your code }; 
object o = d; 
string[] propertyNames = o.GetType().GetProperties().Select(p => p.Name).ToArray(); 
foreach (var prop in propertyNames) 
{ 
    object propValue = o.GetType().GetProperty(prop).GetValue(o, null); 
} 
+1

To zadziałało dla mnie, co nie udało mi się uzyskać dla typu dynamicznego, dzięki –

+0

Działa to tylko wtedy, gdy d jest statycznym typem. Jeśli D jest obiektem IDynamicMetaObjectProvider (takim jak JObject), otrzymasz błędne właściwości. Na przykład, jeśli d = obj, to nie zwróci "x", zwróci surowe właściwości na JObject. JObject obj = JObject.FromObject (nowy { x = 123 }); –

5
string json = w.JSON; 

var serializer = new JavaScriptSerializer(); 
serializer.RegisterConverters(new[] { new DynamicJsonConverter() }); 

DynamicJsonConverter.DynamicJsonObject obj = 
     (DynamicJsonConverter.DynamicJsonObject)serializer.Deserialize(json, typeof(object)); 

Teraz obj._Dictionary zawiera słownik. Idealny!

Kod ten musi być stosowany w połączeniu z Deserialize JSON into C# dynamic object? + dokonać _dictionary zmiennej z „prywatnej ReadOnly” do publicznej wiadomości w kodzie tam

18

nadzieję, że to będzie pomóc:

public static object GetProperty(object o, string member) 
{ 
    if(o == null) throw new ArgumentNullException("o"); 
    if(member == null) throw new ArgumentNullException("member"); 
    Type scope = o.GetType(); 
    IDynamicMetaObjectProvider provider = o as IDynamicMetaObjectProvider; 
    if(provider != null) 
    { 
     ParameterExpression param = Expression.Parameter(typeof(object)); 
     DynamicMetaObject mobj = provider.GetMetaObject(param); 
     GetMemberBinder binder = (GetMemberBinder)Microsoft.CSharp.RuntimeBinder.Binder.GetMember(0, member, scope, new CSharpArgumentInfo[]{CSharpArgumentInfo.Create(0, null)}); 
     DynamicMetaObject ret = mobj.BindGetMember(binder); 
     BlockExpression final = Expression.Block(
      Expression.Label(CallSiteBinder.UpdateLabel), 
      ret.Expression 
     ); 
     LambdaExpression lambda = Expression.Lambda(final, param); 
     Delegate del = lambda.Compile(); 
     return del.DynamicInvoke(o); 
    }else{ 
     return o.GetType().GetProperty(member, BindingFlags.Public | BindingFlags.Instance).GetValue(o, null); 
    } 
} 
+0

Czy możesz wyjaśnić ten kod? – Ewerton

+0

@Ewerton Minęło sporo czasu, ale widzę, że używa * System.Linq.Expressions * do wiązania dynamicznego gettera do strony wywołania i pozostawia kompilację do * LambdaExpression *. Nie wiem, czy wziąłem to z dekompilowanego kodu, czy gdzieś indziej. – IllidanS4

2

Czy ty zobacz klasy ExpandoObject?

Bezpośrednio z MSDN description: "Reprezentuje obiekt, którego członkowie mogą być dynamicznie dodawane i usuwane w czasie wykonywania."

Dzięki niemu można napisać kod tak:

dynamic employee = new ExpandoObject(); 
employee.Name = "John Smith"; 
((IDictionary<String, Object>)employee).Remove("Name"); 
+0

Nazwy właściwości nie są znane, więc to nie zadziała. – user3285954

+0

Kod działa (sprawdziłem to w visual studio), ponieważ instancja pracownika jest obiektem ExpandoObject, więc istnieje możliwość dodawania i usuwania właściwości w czasie wykonywania (jak wyjaśniono w oficjalnej dokumentacji MS). Ten kod spełnia pytanie. – ADIMO

0

że to może komuś pomóc w przyszłości.

Jeśli znasz już nazwę właściwości, można zrobić coś jak następuje:

[HttpPost] 
[Route("myRoute")] 
public object SomeApiControllerMethod([FromBody] dynamic args){ 
    var stringValue = args.MyPropertyName.ToString(); 
    //do something with the string value. If this is an int, we can int.Parse it, or if it's a string, we can just use it directly. 
    //some more code here.... 
    return stringValue; 
} 
+0

Nazwy właściwości nie są znane. – user3285954

0

IF d został stworzony przez Newtonsoft można to wykorzystać, aby odczytać nazwy i wartości własności:

foreach (JProperty property in d) 
    { 
     DoSomething(property.Name, property.Value); 
    } 
Powiązane problemy