2010-03-12 8 views
12

Questo è qualcosa che ho risolto usando il reflection, ma vorrei vedere come farlo usando gli alberi di espressione.Come posso usare un albero di espressioni per chiamare un metodo generico quando il tipo è noto solo al runtime?

Ho una funzione generica:

private void DoSomeThing<T>(param object[] args) { 
    // Some work is done here. 
} 

che ho bisogno di chiamare da un'altra parte nella mia classe. Ora, normalmente, questo sarebbe essere semplice:

DoSomeThing<int>(blah); 

ma solo se lo so, in fase di progettazione che sto lavorando con una int. Quando non conosco il tipo fino al runtime è dove ho bisogno dell'aiuto. Come ho detto, so come farlo attraverso la riflessione, ma mi piacerebbe farlo attraverso gli alberi di espressione, poiché la mia comprensione (molto limitata) è che posso farlo.

Eventuali suggerimenti o punti ai siti in cui è possibile ottenere questa comprensione, preferibilmente con codice di esempio?

risposta

6

MethodInfo.MakeGenericMethod

Poi basta creare un delegato e lo chiamano. (non in un'espressione, naturalmente; p)

Aggiornamento:

In generale, io preferisco usare tipi generici per questo, Activator.CreateInstance richiede solo meno lavoro. Tutto dipende però dalla tua situazione.

+1

Come ho detto, io so come farlo attraverso la riflessione. Sto tentando di fare attraverso gli alberi di espressione. –

+1

Lo stesso, non è vero? Mi sto perdendo qualcosa? (Risposta aggiornata) – leppie

5

Sì, può essere eseguito tramite alberi di espressione. Il vantaggio è che si ottiene un delegato in modo che le chiamate ripetute siano molto più veloci rispetto a fare MethodInfo.Invoke() più e più volte. La parola chiave dynamic può fare anche questo.

Esempio:

What type would you like to use? 
decimal 
Selected type 'System.Decimal' 
Input Value: 
5.47 
<<<USING object>>> 
The object has static type 'System.Object', dynamic type 'System.Decimal', and value '5.47' 
<<<USING dynamic>>> 
The object has static type 'System.Decimal', dynamic type 'System.Decimal', and value '5.47' 
<<<USING reflection>>> 
The object has static type 'System.Decimal', dynamic type 'System.Decimal', and value '5.47' 
<<<USING expression tree>>> 
The object has static type 'System.Decimal', dynamic type 'System.Decimal', and value '5.47' 

Codice:

using System; 
using System.ComponentModel; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Reflection; 

namespace SO2433436 
{ 
    class Program 
    { 
     static void LogObject<T>(T t) 
     { 
      Console.WriteLine("The object has static type '" + typeof(T).FullName + "', dynamic type '" + t.GetType() + "', and value '" + t.ToString() + "'"); 
     } 

     static void Main(string[] args) 
     { 
      Console.WriteLine("What type would you like to use?"); 
      string typeName = Console.ReadLine(); 

      Type userType; 
      switch (typeName) 
      { 
       case "byte": userType = typeof(byte); break; 
       case "sbyte": userType = typeof(sbyte); break; 
       case "ushort": userType = typeof(ushort); break; 
       case "short": userType = typeof(short); break; 
       case "uint": userType = typeof(uint); break; 
       case "int": userType = typeof(int); break; 
       case "string": userType = typeof(string); break; 
       case "decimal": userType = typeof(decimal); break; 
       default: 
        userType = Type.GetType(typeName); 
        break; 
      } 

      Console.WriteLine("Selected type '" + userType.ToString() + "'"); 

      Console.WriteLine("Input Value:"); 
      string val = Console.ReadLine(); 

      object o = TypeDescriptor.GetConverter(userType).ConvertFrom(val); 

      Console.WriteLine("<<<USING object>>>"); 
      LogObject(o); 

      Console.WriteLine("<<<USING dynamic>>>"); 
      LogObject((dynamic)o); 

      Console.WriteLine("<<<USING reflection>>>"); 
      Action<object> f = LogObject<object>; 
      MethodInfo logger = f.Method.GetGenericMethodDefinition().MakeGenericMethod(userType); 
      logger.Invoke(null, new[] { o }); 

      Console.WriteLine("<<<USING expression tree>>>"); 
      var p = new[] { Expression.Parameter(typeof(object)) }; 
      Expression<Action<object>> e = 
       Expression.Lambda<Action<object>>(
        Expression.Call(null, 
            logger, 
            Expression.Convert(p[0], userType) 
            ) 
       , p); 
      Action<object> a = e.Compile(); 
      a(o); 
     } 
    } 
} 
Problemi correlati