2010-03-12 3 views
12

Das habe ich mit Reflektion gelöst, würde aber gerne sehen, wie man das mit Expression-Bäumen macht.Wie kann ich einen Ausdrucksbaum verwenden, um eine generische Methode aufzurufen, wenn der Typ nur zur Laufzeit bekannt ist?

Ich habe eine generische Funktion:

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

, die ich von sonst wo in meiner Klasse anrufen müssen.

DoSomeThing<int>(blah); 

aber nur, wenn ich weiß, zur Design-Zeit, die ich arbeite mit einem int: Nun, normalerweise wäre dies einfach sein wird. Wenn ich den Typ erst zur Laufzeit kenne, brauche ich die Hilfe. Wie ich schon sagte, ich weiß, wie man es durch Reflektion macht, aber ich würde es gerne über Ausdrucksbäume tun, da mein (sehr begrenztes) Verständnis ist, dass ich es tun kann.

Irgendwelche Vorschläge oder Punkte zu Seiten, wo ich dieses Verständnis bekommen kann, vorzugsweise mit Beispielcode?

Antwort

6

MethodInfo.MakeGenericMethod

Dann erstellen Sie einfach einen Delegierten und es nennen. (nicht in einem Ausdruck, natürlich; p)

Update:

Im Allgemeinen ziehe ich diese generische Typen zu verwenden, braucht Activator.CreateInstance nur weniger Arbeit. Alles hängt jedoch von Ihrer Situation ab.

+1

Wie ich bereits sagte, ich weiß, wie es durch Reflexion zu tun. Ich versuche in Via Expression Trees zu tun. –

+1

Genauso ist es, oder? Fehle ich etwas? (Aktualisierte Antwort) – leppie

5

Ja, es kann über Ausdrucksbäume getan werden. Der Vorteil ist, dass Sie einen Delegierten bekommen, so dass wiederholte Anrufe viel schneller sind als MethodInfo.Invoke() immer wieder zu tun. Das Schlüsselwort dynamic kann dies auch tun.

Beispiel:

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' 

Code:

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); 
     } 
    } 
} 
Verwandte Themen