2010-07-05 74 views
2

好了先解釋規則:如何從extression樹參數數組運行參數的信息

我需要構建一個委託匹配一個封裝體的調用類型的委託(任何委託類型的函數Object)(Object [] args)與'args'包含調用期間傳遞給原始委託的所有參數。

我迄今爲止的工作:

delegate void TestDelegate(int x, int y); 
    delegate object TestDelegate2(object[] args); 

    static void Main(string[] sargs) 
    { 
     TestDelegate d = (TestDelegate)CreateAnonymousFromType(typeof(TestDelegate)); 
     object ret = d.DynamicInvoke(2, 6); 

     if (ret != null) { Console.WriteLine(ret); } 

     Console.ReadKey(); 
    } 

    static void SpecialInvoke(int x, int y) 
    { 
     Console.WriteLine("x: {0}\r\ny: {1}", x, y); 
    } 

    static Delegate CreateAnonymousFromType(Type type) 
    { 
     MethodInfo method = type.GetMethod("Invoke"); 

     TestDelegate2 _delegate = new TestDelegate2(
      delegate(object[] args) 
      { 
       Console.WriteLine("x: {0}\r\ny: {1}", args[0], args[1]); 
       return "This is the return"; 
      }); 


     var typeargs = CreateArgs(method.GetParameters()); 
     var argindex = -1; 

     var tmp = Expression.Parameter(typeof(Object), "tmp"); 
     var index = Expression.Parameter(typeof(int), "index"); 

     var length = Expression.Constant(typeargs.Length); 

     var _break = Expression.Label("breakto"); 

     var delegateargs = Expression.Parameter(typeof(object[]), "args"); 

     return Expression.Lambda(
      type, 
      Expression.Block(
       new[] { tmp, index, delegateargs }, 
       Expression.Assign(index, Expression.Constant(0)), 
       Expression.Assign(delegateargs, Expression.NewArrayBounds(typeof(Object), length)), 
       Expression.Loop(
        Expression.IfThenElse(Expression.LessThan(index, length), 
         Expression.Block(
          Expression.Assign(tmp, Expression.Convert(typeargs[++argindex], typeof(Object))), 
          Expression.Assign(Expression.ArrayAccess(delegateargs, index), tmp), 
          Expression.PostIncrementAssign(index) 
         ), 
         Expression.Break(_break) 
        ), 
        _break 
       ), 
       Expression.Call(_delegate.Method, delegateargs) 
      ), 
      typeargs 
     ).Compile(); 
    } 

    static ParameterExpression[] CreateArgs(ParameterInfo[] _params) 
    { 
     ParameterExpression[] ret = new ParameterExpression[_params.Length]; 

     for (int i = 0; i < ret.Length; i++) 
      ret[i] = Expression.Parameter(_params[i].ParameterType, _params[i].Name); 

     return ret; 
    } 

現在這SORTA工程...我只得到[0]傳遞給委託「TestDelegate2」這兩個參數x和y的「ARGS typeargs的價值'參數在運行時是對象[] {2,2},我不能爲我的生活找到一種方法來增加參數迭代範圍內的「argindex」...在編譯時參數計數是不確定的。有人知道我可以如何解決這個問題嗎?

我已經試過只複製使用Expression.NewArrayInit參數數組(typeof運算(對象),typeargs),但未能說,它不能使用的Int32初始化對象的數組

我也試過這個: var arguments = Expression.Constant(typeargs);

並且在「index」處訪問「arguments」的值,但是這會產生字符串「x」和「y」..顯然是參數的名稱而不是它們的值。

這是老實說,我第一次使用表達式樹的主要嘗試,所以任何幫助..無論多麼小。將不勝感激。

謝謝。

回答

2

我認爲你是在Expression.NewArrayInit的正確軌道上。你可以修復「類型‘System.Int32’的表達不能被用於初始化類型的‘System.Object的’陣列」的錯誤通過使用Expression.Convert插入每個參數的轉化:

var typeargs = CreateArgs(method.GetParameters()); 
return Expression.Lambda(
    type, 
    Expression.Call(_delegate.Method, Expression.NewArrayInit(typeof(object), 
     typeargs.Select(arg => Expression.Convert(arg, typeof(object))) 
     )), 
    typeargs 
).Compile(); 
+0

甜!我知道必須有某種解決方案......很容易找到有關製作基本表達式樹的信息,但很少了解如何使用參數以及如何在後續表達式塊中使用參數的表達式。這工作完美!而代碼是很多行短..讚揚! =) – SilverX 2010-07-05 21:37:04