2009-12-18 14 views
8

Sì, il titolo sembra un po 'confuso, quindi spiegherò cosa intendo: supponiamo di avere un oggetto "dinamico" C# 4.0 e il nome di una proprietà. Come recupereresti quella proprietà dall'oggetto dinamico?Ottenere dinamicamente un valore da un oggetto dinamico

In altre parole, come si potrebbe implementare:

public static object GetDynamicValue(dynamic o, string name) { ... } 

Un altro modo di metterla è che sto cercando di trattare un oggetto dinamico come un IDictionary.

Si noti che la riflessione non è probabilmente un'opzione qui, poiché l'oggetto dinamico potrebbe essere un'implementazione personalizzata che non è basata sulla riflessione (ad esempio estendendo DynamicObject e facendo la propria cosa).

+1

Si può dire un po 'di più sul vostro caso d'uso? Se si desidera avere un oggetto dinamico simile a IDictionary, perché non utilizzare ExpandoObject, ad esempio? Il suggerimento di Jon probabilmente funziona, ma ho la sensazione che questa sia una soluzione troppo complicata per quello che stai cercando di fare. –

risposta

13

Si dovrà costruire un sito chiamata, creare un legante ecc

Il modo più semplice per vedere cosa succede è quello di compilare questo:

public static object GetDynamicValue(dynamic o, string name) 
{ 
    return o.Foo; 
} 

Poi decompilare con riflettore e capire cosa sta facendo Sarà piuttosto complicato, badate bene - e avrete bisogno di cambiarlo da un singolo sito di chiamata memorizzato nella cache, per crearne uno nuovo su ogni invocazione.

Ecco un esempio che funziona ... ma se si tratta di tutto corretta o meno è un altro discorso :) (Ho avuto questa intenzione facendo esattamente quello che ho suggerito sopra.)

using Microsoft.CSharp.RuntimeBinder; 
using System; 
using System.Dynamic; 
using System.Runtime.CompilerServices; 

class Test 
{ 
    public static object GetDynamicValue(dynamic o, string name) 
    { 
     CallSite<Func<CallSite, object, object>> site 
      = CallSite<Func<CallSite, object, object>>.Create 
      (Binder.GetMember(CSharpBinderFlags.None, name, 
      typeof(Test), new CSharpArgumentInfo[] 
      { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) })); 
     return site.Target(site, o); 
    } 

    static void Main() 
    { 
     Console.WriteLine(GetDynamicValue("hello", "Length")); 
    } 
} 
+0

Molto carino, grazie Jon! Ciò porta molti concetti che non ho affrontato, quindi dovrò studiarlo attentamente. Sembra strano che typeof (Test) sia usato lì, poiché non dovrebbe essere rilevante. Ma ho provato a impostarlo su null e il codice funziona ancora, quindi apparentemente non stava facendo molto. –

+3

È pertinente in termini di quali membri sono accessibili - sarete in grado di ottenere membri privati ​​di Test usando questo codice, ma non membri privati ​​di altri tipi. –

3

Il Il framework Open Source ImpromptuInterface (disponibile in nuget) esegue questa operazione e svolge il lavoro aggiuntivo perché la memorizzazione nella cache del sito di chiamata è importante per le prestazioni.

Vedi InvokeGet

public static object GetDynamicValue(dynamic o, string name) { 
     return Impromptu.InvokeGet(o,name); 
} 
+0

Anche Clay fa qualcosa del genere (http://clay.codeplex.com/) –

+0

@ David-Ebbo Mentre Clay ti permette di accedere alle sue proprietà tramite il nome della stringa, 'InvokeGet' ti permette di accedere a QUALSIASI proprietà di IDynamicMetaObjectProvider tramite il nome della stringa (o qualsiasi oggetto normale più veloce di quella riflessione) ... a meno che mi manchi qualcosa. – jbtule

Problemi correlati