8

Ich bin auf der Suche nach einer Möglichkeit, Mitglieder dynamisch zu einem dynamischen Objekt hinzuzufügen. OK, ich denke, ein wenig Klärung benötigt ...Mitglieder dynamisch zu einem dynamischen Objekt hinzufügen

Wenn Sie das tun:

dynamic foo = new ExpandoObject(); 
foo.Bar = 42; 

Die Bar Eigenschaft wird zur Laufzeit dynamisch hinzugefügt werden. Aber der Code bezieht sich immer noch "statisch" auf Bar (der Name "Bar" ist fest codiert) ... Was, wenn ich eine Eigenschaft zur Laufzeit hinzufügen möchte, ohne ihren Namen zur Kompilierzeit zu kennen?

Ich weiß, wie dies zu tun mit einem benutzerdefinierten dynamischen Objekt (I blogged about it tatsächlich vor ein paar Monaten), die Methoden der DynamicObject-Klasse, aber wie kann ich es mit jedes dynamischen Objekt?

Ich könnte wahrscheinlich die IDynamicMetaObjectProvider Schnittstelle verwenden, aber ich verstehe nicht, wie man es benutzt. Zum Beispiel, welches Argument sollte ich an die GetMetaObject Methode weitergeben? (es erwartet ein Expression)

Und übrigens, wie führen Sie Reflexion über dynamische Objekte? "Regular" Reflexion und TypeDescriptor zeigen nicht die dynamischen Mitglieder ...

Jeder Einblick würde uns freuen!

+0

In C# 6.0, * kann sein * Sie können es wie 'foo schreiben. $ Bar = 42;' :) Nicht sicher, ob es für dynamische erlaubt ist ... – nawfal

+0

@Nawfal, eigentlich, diese Funktion wurde gelöscht .. Aber egal, 'foo. $ Bar' ist nur eine Abkürzung für' foo ["Bar"] ' –

+0

Thomas, wusste nicht, dass die Funktion gelöscht wurde (ich bin froh darüber), aber oh ja, für einen Moment Ich habe die wirkliche Anforderung deines q übersehen. – nawfal

Antwort

9

Was Sie wollen, ist ähnlich wie Python getattr/setattr Funktionen. Es gibt keine integrierte Möglichkeit, dies in C# oder VB.NET zu tun. Die äußere Schicht des DLR (die mit IronPython und IronRuby in Microsoft.Scripting.dll ausgeliefert wird) enthält eine Reihe von Hosting-APIs, die eine ObjectOperations-API mit GetMember/SetMember-Methoden enthalten. Sie könnten diese verwenden, aber Sie würden die zusätzliche Abhängigkeit des DLR und einer DLR-basierten Sprache benötigen.

Der wahrscheinlich einfachste Ansatz wäre, eine CallSite mit einem der vorhandenen C# -Binder zu erstellen. Sie können den Code dafür erhalten, indem Sie das Ergebnis von "foo.Bar = 42" in ildasm oder Reflektor betrachten. Aber ein einfaches Beispiel dafür wäre:

object x = new ExpandoObject(); 
CallSite<Func<CallSite, object, object, object>> site = CallSite<Func<CallSite, object, object, object>>.Create(
      Binder.SetMember(
       Microsoft.CSharp.RuntimeBinder.CSharpBinderFlags.None, 
       "Foo", 
       null, 
       new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) } 
      ) 
     ); 
site.Target(site, x, 42); 
Console.WriteLine(((dynamic)x).Foo); 
+0

Ich brauche etwas Zeit, um sicherzustellen, dass ich wirklich verstehe, was dieser Code macht, aber trotzdem funktioniert es gut ... Danke! –

+0

Wäre es möglich, dies <.Net 4.0 mit dem DLR zu tun? Es scheint, dass die Verwendung von dynamischen dies ausschließen würde. – Firestrand

+0

Die obige Methode sollte nicht richtig funktionieren. Setter Aufrufort erfordert 2 Argument Infos statt 1. Die richtige Definition zur Verfügung gestellt werden wird: new [] { CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create (CSharpArgumentInfoFlags.None, null) } –

5

Die Open-Source-Framework Dynamitey (via nuget verfügbar), wird dies tun. Es kapselt den Cachestandort und den Binder-Code, den @ Dino-Viehland verwendet hat.

Dynamic.InvokeSet(foo,"Bar",42); 

Es kann auch viele other kinds of c# binder too anrufen.

5

ExpandoObject implementiert IDictionary < Zeichenfolge, Objekt >, obwohl explizit. Dies bedeutet, dass Sie das ExpandoObject einfach in IDictionary < string, Objekt > umwandeln und das Wörterbuch bearbeiten können.

dynamic foo = new ExpandoObject(); 
foo.Bar = 42; 
food = (IDictionary<string,object>)foo; 
food["Baz"] = 54 
+0

Danke! In der Tat implementiert ExpandoObject IDictionary, wie ich später erkannte, also ist es eindeutig die einfachste Lösung in diesem Fall. Der Umfang meiner Frage war jedoch größer: Ich suchte nach einer Lösung, die mit jedem dynamischen Objekt und nicht nur mit ExpandoObject funktionieren würde –

1

Ich weiß, das ist schon eine alte Post, aber ich dachte, ich entlang Miron Abramson solution weitergeben würde, wie Sie Ihre eigene Art erstellen und fügen Sie Eigenschaften zur Laufzeit - bei sonst jemand da draußen nach etwas sucht, ähnlich.

Verwandte Themen