2010-09-22 3 views
7

im Grunde möchte ich die Werte der Parameter einer aufgerufenen Methode wie folgt erhalten:Endwerte von Lambda-Ausdrücke Methode erhalten Parameter

var x = 1; 
var a = 2; 
var b = 3; 
Do<HomeController>(o => o.Save(x, "Jimmy", a+b+5, Math.Sqrt(81))); 

public static void Do<T>(Expression<Action<T>> expression) where T : Controller 
{ 
    // get the values 1,Jimmy,10,9 here 
} 

Antwort

17

Nun, würden Sie müssen in den Ausdruck bohren, finden die MethodCallExpression und dann schauen Sie sich die Argumente an. Beachten Sie, dass wir nicht den Wert o haben, also müssen wir davon ausgehen, dass die Argumente für die Methode nicht darauf angewiesen sind. Auch wir gehen immer noch davon aus, dass der Lambda-Ausdruck nur darauf beruht, dass es ein MethodCallExpression ist?

EDIT: Okay, hier ist eine bearbeitete Version, die die Argumente bewertet. Es nimmt jedoch an, Sie sind nicht wirklich mit dem Lambda-Ausdruck Parameter innerhalb der Argumente (was ist die new object[1] ist über - es bietet einen Null-Parameter, effektiv).

using System; 
using System.Linq.Expressions; 

class Foo 
{ 
    public void Save(int x, string y, int z, double d) 
    { 
    } 
} 

class Program 
{ 
    static void Main() 
    { 
     var x = 1; 
     var a = 2; 
     var b = 3; 
     ShowValues<Foo>(o => o.Save(x, "Jimmy", a + b + 5, Math.Sqrt(81))); 
    } 

    static void ShowValues<T>(Expression<Action<T>> expression) 
    { 
     var call = expression.Body as MethodCallExpression; 
     if (call == null) 
     { 
      throw new ArgumentException("Not a method call"); 
     } 
     foreach (Expression argument in call.Arguments) 
     { 
      LambdaExpression lambda = Expression.Lambda(argument, 
                 expression.Parameters); 
      Delegate d = lambda.Compile(); 
      object value = d.DynamicInvoke(new object[1]); 
      Console.WriteLine("Got value: {0}", value); 
     } 
    } 
} 
+2

@Omu: Aber wollen Sie wirklich Code, der brechen würde - zur Ausführungszeit nur - wenn Sie * any * andere Form von Lambda-Ausdruck verwendet? Wenn Sie immer Save aufrufen, warum übergeben Sie die Parameter nicht einfach direkt? –

+0

@ Jon Skeet, ich werde viele andere Methoden mit verschiedenen Parametern aufrufen, wusste ich nicht, dass ich nur mit konstanten Werten aufrufen kann, ich denke, ich werde dies weiter untersuchen müssen – Omu

+0

@Omu: Dies ist das Problem, wenn man einfach Code in eine Frage ohne Erklärung steckt. Ich habe * sagen * es war spröde, und würde scheitern, sobald Sie anfangen, irgendein anderes Muster zu verwenden ... –

4

Wie Jon gesagt, Sie, wenn der Ausdruck ein Method

ist zu sehen, überprüfen sind
class Program 
{ 
    static void Main(string[] args) 
    { 
     Program.Do<Controller>(c => c.Save(1, "Jimmy")); 
    } 

    public static void Do<T>(Expression<Action<T>> expression) where T : Controller 
    { 
     var body = expression.Body as MethodCallExpression; 
     if (body != null) 
     { 
      foreach (var argument in body.Arguments) 
      { 
       var constant = argument as ConstantExpression; 
       if (constant != null) 
       { 
        Console.WriteLine(constant.Value); 
       } 
      } 
     } 
    } 
} 

public class Controller 
{ 
    public void Save(int id, string name) 
    { 
    } 
} 
+0

Ich liebe die Tatsache, dass unser Demo-Code fast identisch ist :) –

+0

@Jon, ich hatte keine Zeit, um Fehler zu überprüfen tho :( –

+0

Ja, es ist ziemlich spröde oder so. Ich bezweifle, es ist der beste Ansatz, aber wir habe nicht viel Kontext –

2

Hier einige Code, der mit jedem Ausdruck arbeiten ausgelegt ist - in dem Sinne, dass es nicht im Grunde tut Angenommen, Sie übergeben einen Methodenaufruf-Ausdruck. Es ist jedoch nicht vollständig. Sie müssen den Rest ausfüllen.

public static IEnumerable<object> ExtractConstants<T>(
     Expression<Action<T>> expression) 
{ 
    return extractConstants(expression); 
} 
private static IEnumerable<object> extractConstants(Expression expression) 
{ 
    if (expression == null) 
     yield break; 

    if (expression is ConstantExpression) 
     yield return ((ConstantExpression) expression).Value; 

    else if (expression is LambdaExpression) 
     foreach (var constant in extractConstants(
       ((LambdaExpression) expression).Body)) 
      yield return constant; 

    else if (expression is UnaryExpression) 
     foreach (var constant in extractConstants(
       ((UnaryExpression) expression).Operand)) 
      yield return constant; 

    else if (expression is MethodCallExpression) 
    { 
     foreach (var arg in ((MethodCallExpression) expression).Arguments) 
      foreach (var constant in extractConstants(arg)) 
       yield return constant; 
     foreach (var constant in extractConstants(
       ((MethodCallExpression) expression).Object)) 
      yield return constant; 
    } 

    else 
     throw new NotImplementedException(); 
} 

Für den Fall, dass Sie erwähnt haben, funktioniert dies bereits:

// Prints: 
// Jimmy (System.String) 
// 1 (System.Int32) 
foreach (var constant in Ext.ExtractConstants<string>(
     str => Console.WriteLine("Jimmy", 1))) 
    Console.WriteLine("{0} ({1})", constant.ToString(), 
            constant.GetType().FullName); 

Für komplexere Lambda-Ausdrücke, die andere Typen von Expressions Knoten verwenden, werden Sie schrittweise den obigen Code erweitern müssen. Jedes Mal, wenn Sie es verwenden, und es wirft ein NotImplementedException, hier ist das, was ich tue:

  • Öffnen Sie das Fenster Uhr im Debugger
  • Blick auf die expression Variable und den Typ
  • den erforderlichen Code hinzufügen zu handhaben dieser Ausdruckstyp

Im Laufe der Zeit wird die Methode immer vollständiger.

2

Meine universelle Antwort ist unten. Ich hoffe, es wird dir und jemand anderem helfen.

var dict = new Dictionary<string, object>(); 
var parameterExpressions = methodCallExpr.Arguments; 
foreach (var param in method.GetParameters()) 
{ 
    var parameterExpression = parameterExpressions[counter]; 
    var paramValueAccessor = Expression.Lambda(parameterExpression); 
    var paramValue = paramValueAccessor.Compile().DynamicInvoke(); 
    dict[param.Name] = paramValue; 
} 
0
public override IQueryable<Image> FindAll(System.Linq.Expressions.Expression<Func<Image, dynamic>> Id) 
     { 
      dynamic currentType = Id.Parameters[0]; 
      var id = currentType.Type.GUID; 
      var result = (_uniwOfWork as UnitOfWork).uspGetImages(id.ToString()); 
      return FindAll(); 
     } 

Verwendung Stichwort dynamisch.

Verwandte Themen