2015-12-18 11 views
5

すべてのタイプの代理人用のラッパーを作成するメソッドを(実行時に)作成しようとしています。これは、追加のロギング(この場合)を注入する柔軟な方法を作成するためです。この最初のステップでは、与えられたinput - 引数の周りにtry-catchラップを作成しようとしました。スコープ ''から参照されている 'System.Boolean'型の変数 ''は定義されていません」式

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

私は、このコードは私が必要なものを行い、一般的なメソッド呼び出しCreateWrapper2(下記参照)(Action<>のような)空隙の方法については

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

を使用しています。しかし、戻り値があるとき、私は例外を取得「『タイプの『』変数可能System.Boolean』スコープから参照 『』が、に定義されていません」

多くの他の記事を約Expression.Parameter回以上呼ばれる話パラメータの場合。私にはここのように見えますが、他の何かがここに間違っていますが、私はそれを見つけることができません。 .Compile行まではすべてうまく行きますが、そこではクラッシュします。

Func<int, bool> target = i => i % 2 ==0;は、生成された式のDebugViewです。

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

何が欠けていますか?

    • がトップレベルしようと、体内からExpression.Variableを移動typed-介しキャッチブロックを試しブロックと同じBody.Typeを与えた:。 (デバッグ時間中に私が試みExpression.Return

  • 答えて

    0

    あなたはブロック文のためにあなたのvaraiblesを指定していないように見えます。あなたはその場でパラメータを作成し、名前を与えていない、あなたがやった場合は、見ているだろうしているエラーで

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

    ので、今後の参考のためであれば、あなたの人生がずっと簡単にすることができます表現木を作るときにあなたのvarsの名前をつけてください。

     // 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(); 
    
    関連する問題