2015-12-18 11 views
5

Sto provando a creare un metodo per (in fase di esecuzione) la creazione di wrapper per i delegati di tutti i tipi. Questo per creare un modo flessibile di inserire registrazioni aggiuntive (in questo caso). In questo primo passo ho provato a creare un wrap try-catch attorno allo specifico argomento input."variabile '' di tipo 'System.Boolean' referenziato dall'ambito '', ma non è definito" in Expression

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

Sto usando una chiamata di metodo generico CreateWrapper2 (vedi sotto)

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(); 
} 

Per Void-metodi (come Action<>) questo codice fa quello che mi serve. Ma quando c'è un valore di ritorno ottengo l'eccezione "variabile '' di tipo 'System.Boolean' referenziato dal campo di applicazione '', ma non è definito"

Molti altri messaggi parlare Expression.Parameter chiamato più di una volta per un parametro; a me sembra che qui c'è qualcos'altro che non va, ma non riesco a trovarlo. Tutto va bene fino alla riga .Compile, lì si blocca.

Per un Func<int, bool> target = i => i % 2 ==0; di seguito è il DebugView per l'espressione generata.

.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: 
    } 
} 

Cosa mi manca? (durante le ore di debug ho provato:

  • spostando il Expression.Variable dall'interno del try-corpo al toplevel
  • dato il fermo-blocco stesso Body.Type come try-block tramite il typed-. Expression.Return.

)

risposta

0

sembra che non si sta specificando il vostro varaibles per l'istruzione di blocco.

In l'errore che si sta creando un parametro al volo e non dandogli un nome, se avete fatto che avrebbe visto:

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

Così, per riferimento futuro può rendere la vita molto più facile se date i nomi dei vostri varsari quando create alberi di espressione, il seguente dovrebbe funzionare

 // 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(); 
Problemi correlati