2015-12-18 8 views
5

Ich versuche eine Methode zu erstellen (zur Laufzeit) Wrapper für Delegaten aller Typen zu erstellen. Dies schafft eine flexible Möglichkeit, zusätzliche Protokollierung (in diesem Fall) zu injizieren. In diesem ersten Schritt habe ich versucht, einen Try-Catch-Wrap um das gegebene Argument zu erstellen."Variable '' vom Typ 'System.Boolean' referenziert aus Bereich '', aber es ist nicht definiert" in Ausdruck

try 
{ 
    Console.WriteLine(....); 
    // Here the original call 
    Console.WriteLine(....); 
} 
catch(Exception ex) 
{ 
    Console.WriteLine(.....); 
} 

Ich bin einen generischen Methodenaufruf mit CreateWrapper2 (siehe unten)

private static readonly MethodInfo ConsoleWriteLine = typeof(Console).GetMethod("WriteLine", new[] { typeof(string), typeof(object[]) }); 

private static MethodCallExpression WriteLinExpression(string format, params object[] args) 
{ 
    Expression[] expressionArguments = new Expression[2]; 
    expressionArguments[0] = Expression.Constant(format, typeof(string)); 
    expressionArguments[1] = Expression.Constant(args, typeof(object[])); 

    return Expression.Call(ConsoleWriteLine, expressionArguments); 
} 

public T CreateWrapper2<T>(T input) 
{ 
    Type type = typeof(T); 

    if (!typeof(Delegate).IsAssignableFrom(type)) 
    { 
     return input; 
    } 

    PropertyInfo methodProperty = type.GetProperty("Method"); 
    MethodInfo inputMethod = methodProperty != null ? (MethodInfo)methodProperty.GetValue(input) : null; 

    if (inputMethod == null) 
    { 
     return input; 
    } 

    string methodName = inputMethod.Name; 
    ParameterInfo[] parameters = inputMethod.GetParameters(); 
    ParameterExpression[] parameterExpressions = new ParameterExpression[parameters.Length]; 

    // TODO: Validate/test parameters, by-ref /out with attributes etc. 

    for (int idx = 0; idx < parameters.Length; idx++) 
    { 
     ParameterInfo parameter = parameters[idx]; 
     parameterExpressions[idx] = Expression.Parameter(parameter.ParameterType, parameter.Name); 
    } 

    bool handleReturnValue = inputMethod.ReturnType != typeof(void); 

    ParameterExpression variableExpression = handleReturnValue ? Expression.Variable(inputMethod.ReturnType) : null; 
    MethodCallExpression start = WriteLinExpression("Starting '{0}'.", methodName); 
    MethodCallExpression completed = WriteLinExpression("Completed '{0}'.", methodName); 
    MethodCallExpression failed = WriteLinExpression("Failed '{0}'.", methodName); 

    Expression innerCall = Expression.Call(inputMethod, parameterExpressions); 
    LabelTarget returnTarget = Expression.Label(inputMethod.ReturnType); 
    LabelExpression returnLabel = Expression.Label(returnTarget, Expression.Default(returnTarget.Type)); ; 
    GotoExpression returnExpression = null; 

    if (inputMethod.ReturnType != typeof(void)) 
    { 
     // Handle return value. 
     innerCall = Expression.Assign(variableExpression, innerCall); 
     returnExpression = Expression.Return(returnTarget, variableExpression, returnTarget.Type); 
    } 
    else 
    { 
     returnExpression = Expression.Return(returnTarget); 
    } 

    List<Expression> tryBodyElements = new List<Expression>(); 
    tryBodyElements.Add(start); 
    tryBodyElements.Add(innerCall); 
    tryBodyElements.Add(completed); 

    if (returnExpression != null) 
    { 
     tryBodyElements.Add(returnExpression); 
    } 

    BlockExpression tryBody = Expression.Block(tryBodyElements); 
    BlockExpression catchBody = Expression.Block(tryBody.Type, new Expression[] { failed, Expression.Rethrow(tryBody.Type) }); 
    CatchBlock catchBlock = Expression.Catch(typeof(Exception), catchBody); 
    TryExpression tryBlock = Expression.TryCatch(tryBody, catchBlock); 

    List<Expression> methodBodyElements = new List<Expression>(); 

    if(variableExpression != null) methodBodyElements.Add(variableExpression); 

    methodBodyElements.Add(tryBlock); 
    methodBodyElements.Add(returnLabel); 

    Expression<T> wrapperLambda = Expression<T>.Lambda<T>(Expression.Block(methodBodyElements), parameterExpressions); 

    Console.WriteLine("lambda:"); 
    Console.WriteLine(wrapperLambda.GetDebugView()); 

    return wrapperLambda.Compile(); 
} 

Für hohlraum Methoden (wie Action<>) dieser Code tut, was ich brauche. Aber wenn es ein Rückgabewert bekomme ich die Ausnahme „Variable‚‘vom Typ‚System.Boolean‘von Umfang verwiesen wird‚‘, aber es ist nicht definiert“

Viele andere Beiträge sprechen über Expression.Parameter mehr als einmal aufgerufen für einen Parameter; für mich sieht es so aus als ob hier etwas anderes falsch ist aber ich kann es nicht finden. Alles geht gut bis zur .Compile Linie, dort stürzt es ab.

Für eine Func<int, bool> target = i => i % 2 ==0; unten ist das DebugView für den generierten Ausdruck.

.Lambda #Lambda1<System.Func`2[System.Int32,System.Boolean]>(System.Int32 $i) { 
    .Block() { 
     $var1; 
     .Try { 
      .Block() { 
       .Call System.Console.WriteLine(
        "Starting '{0}'.", 
        .Constant<System.Object[]>(System.Object[])); 
       $var1 = .Call LDAP.LdapProgram.<Main>b__0($i); 
       .Call System.Console.WriteLine(
        "Completed '{0}'.", 
        .Constant<System.Object[]>(System.Object[])); 
       .Return #Label1 { $var1 } 
      } 
     } .Catch (System.Exception) { 
      .Block() { 
       .Call System.Console.WriteLine(
        "Failed '{0}'.", 
        .Constant<System.Object[]>(System.Object[])); 
       .Rethrow 
      } 
     }; 
     .Label 
      .Default(System.Boolean) 
     .LabelTarget #Label1: 
    } 
} 

Was fehlt mir? (während des Debuggens Stunden ich versucht:

  • zum Toplevel die Expression.Variable aus dem Inneren des Anprobe Körper bewegen
  • gab dem Catch-Block das gleiche wie der Body.Type try-Block über den typed-. Expression.Return.

)

Antwort

0

Es ist wie Sie Ihre varaibles für den Block-Anweisung spezifiziert sind nicht sieht.

Im Fehler, den Sie im Fluge einen Parameter sind zu schaffen und es keinen Namen geben, wäre, wenn Sie getan haben Sie gesehen:

"variable 'varName' of type 'System.Boolean' referenced from scope 'varName', but it is not defined" 

So zum späteren Nachschlagen auf Ihr Leben viel einfacher machen können, wenn Geben Sie beim Erstellen von Ausdrucksbäumen Ihre Variablennamen ein, die folgendermaßen funktionieren sollten

 // Define the variable at the top of the block 
     // when we are returning something 
     if (variableExpression != null) 
     { 
      block = Expression.Block(new[] { variableExpression }, methodBodyElements); 
     } 
     else 
     { 
      block = Expression.Block(methodBodyElements); 
     } 

     Expression<T> wrapperLambda = Expression<T>.Lambda<T>(block, parameterExpressions); 

     return wrapperLambda.Compile(); 
Verwandte Themen