DynamicExpression:表示動態操作。這個網上可見的資料少得可憐,但想到MVC和第三方的動態語言能在NET運行。好奇的倒騰了下先聲明兩個類(有相同的方法和字段,但不是繼承于同一接口的類),設想是動態調用它們的方法和字段。
class AiTestD { public string Name = "你好!這是 AiTestD"; public int Id = 123; public static string AiTest(string ai1, string ai2) { return ai1 + ai2; } public static int add(int a, int b) { return a + b; } public int add2(int a, int b) { return -(a + b); } } class AiTestD2 { public string Name = "你好!這是 AiTestD2"; public int Id = 789; public static string AiTest(string ai1, string ai2) { return "**" + ai1 + ai2; } public static int add(int a, int b) { return (a + b) * 1000; } public int add2(int a, int b) { return -(a + b) * 1000; } }第一個方法 AiDynamicDo,要實現的是獲取兩個類的Id屬性質(這里是值類型操作,剛開始時,定義的是typeof(Func<CallSite, object, int>,總是編譯不過,發現在 Expression.MakeDynamic 中的參數,只要是值類型都是通不過的,只有通過Expression.Convert轉換成 typeof(object),才可以,但引用類型是不用轉換的)
/// <summary> /// 獲取字段 /// </summary> /// <param name="aiD"></param> static void AiDynamicDo(dynamic aiD) { //聲明參數 ParameterExpression paramExpr = Expression.Parameter(typeof(object), "o"); //獲取 CallSite 以支持調用時的運行時。 //CallSiteBinder 是必需的 //注意這里用的是 Binder.GetMember CallSiteBinder aiBinder = Binder.GetMember(CSharpBinderFlags.None, "Id", typeof(Program), new CSharpArgumentInfo[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); //定義一個動態表達式 //Func<CallSite, object, object>聲明方式中 CallSite 是動態調用站點的基類。 此類型用作動態站點目標的參數類型。 //就是上面的 aiBinder,第二個參數是要傳入的動態類型 用dynamic關鍵字也是可以的, //后面的參數是實際調用和返回的參數 //不過操作中發現在返回值一定要用 object 不然會編譯不過 //當然也可用Action<CallSite, object,...>,除了沒返回值,參數要求和用Func<CallSite, object, object>是一樣的。 DynamicExpression Dynamic2 = Expression.MakeDynamic(typeof(Func<CallSite, object, object>), aiBinder, paramExpr ); //編譯 LambdaExpression laExp = Expression.Lambda( Expression.Block( new ParameterExpression[] { paramExpr }, Expression.Assign(paramExpr, Expression.Constant(aiD)) , Dynamic2)); //執行 Console.WriteLine("AiDynamicDo:" + laExp.ToString()); Console.WriteLine("結果:" + laExp.Compile().DynamicInvoke()); Console.WriteLine(); }調用:
AiDynamicDo(new AiTestD()); AiDynamicDo(new AiTestD2());
輸出為: AiDynamicDo:() => {var o; ... } 結果:123 AiDynamicDo:() => {var o; ... } 結果:789
/// <summary> /// 字段2 /// </summary> /// <param name="aiD"></param> static void AiDynamicDo2(dynamic aiD) { //Binder.Convert CallSiteBinder aiBinder = Binder.Convert(CSharpBinderFlags.None, typeof(object), typeof(Program)); ParameterExpression paramExpr = Expression.Parameter(aiD.GetType(), "o"); MemberExpression namePropExpr = Expression.Field(paramExpr, "Name"); var Dynamic2 = Expression.MakeDynamic(typeof(Func<CallSite, object, object>) , aiBinder , namePropExpr ); LambdaExpression laExp = Expression.Lambda( Expression.Block( new ParameterExpression[] { paramExpr }, Expression.Block(Expression.Assign(paramExpr, Expression.Constant(aiD)) ) , Dynamic2)); Console.WriteLine("AiDynamicDo2:" + laExp.ToString()); Console.WriteLine("結果:" + laExp.Compile().DynamicInvoke()); Console.WriteLine(); } /// <summary> /// 引用類型方法調用測試 Binder.Convert /// </summary> /// <param name="aiD"></param> static void AiDynamicDo3(dynamic aiD) { //Binder.Convert CallSiteBinder aiBinder = Binder.Convert(CSharpBinderFlags.None, typeof(object), typeof(Program)); ParameterExpression aiparamExpr = Expression.Parameter(aiD.GetType(), "o"); ParameterExpression aiParamExpr1 = Expression.Parameter(typeof(string), "a"); ParameterExpression aiParamExpr2 = Expression.Parameter(typeof(string), "b"); MethodCallExpression aiMth = Expression.Call( null, aiD.GetType().GetMethod("AiTest", new Type[] { typeof(string), typeof(string) }), aiParamExpr1, aiParamExpr2); var Dynamic2 = Expression.MakeDynamic( typeof(Func<CallSite, dynamic, object>), aiBinder, aiMth ); LambdaExpression laExp = Expression.Lambda(Dynamic2, aiParamExpr1, aiParamExpr2); Console.WriteLine("AiDynamicDo3:" + laExp.ToString()); Console.WriteLine("結果:" + laExp.Compile().DynamicInvoke("AiTest-", "動態調用")); Console.WriteLine(); } /// <summary> /// 值類型方法調用測試 Binder.Convert /// </summary> /// <param name="aiD"></param> static void AiDynamicDo4(dynamic aiD) { CallSiteBinder aiBinder = Binder.Convert(CSharpBinderFlags.None, typeof(object), typeof(Program)); ParameterExpression aiParamExpr = Expression.Parameter(aiD.GetType(), "o"); ParameterExpression aiParamExpr1 = Expression.Parameter(typeof(int), "a"); ParameterExpression aiParamExpr2 = Expression.Parameter(typeof(int), "b"); MethodCallExpression aiMth = Expression.Call( null, aiD.GetType().GetMethod("add", new Type[] { typeof(int), typeof(int) }), aiParamExpr1, aiParamExpr2); var Dynamic2 = Expression.MakeDynamic( typeof(Func<CallSite, dynamic, object>), aiBinder, Expression.Convert(aiMth, typeof(object)) //!!這里要轉換,否剛不能通過 ); //LambdaExpression laExp = Expression.Lambda(Dynamic2, paramExpr1, paramExpr2); LambdaExpression laExp = Expression.Lambda( Expression.Block( new ParameterExpression[] { aiParamExpr1, aiParamExpr2 }, Expression.Block(Expression.Assign(aiParamExpr1, Expression.Constant(30)), Expression.Assign(aiParamExpr2, Expression.Constant(40)) ), Dynamic2 ) ); Console.WriteLine("AiDynamicDo4:" + laExp.ToString()); Console.WriteLine("結果:" + laExp.Compile().DynamicInvoke()); Console.WriteLine(); } //與上例不同的是,本過程不是調用的反射方法 static void AiDynamicDo5(dynamic aiD) { //當調用方法是void類型時 應該用 CSharpBinderFlags.ResultDiscarded //第二個參數是方法名 //第三個參數要泛型時才結出 //第五個參數要與表達示參數據相同 var aiBinder = Binder.InvokeMember(CSharpBinderFlags.None, "add2", null, typeof(Program), new[] { CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null), CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null) }); ParameterExpression aiParamExpr = Expression.Parameter(typeof(object), "o"); ParameterExpression aiParamExpr1 = Expression.Parameter(typeof(int), "a"); ParameterExpression aiParamExpr2 = Expression.Parameter(typeof(int), "b"); //與上例中不同的地方 DynamicExpression aiDynamic = Expression.MakeDynamic(typeof(Func<CallSite, object, int, int, object>) , aiBinder , aiParamExpr , aiParamExpr1 , aiParamExpr2 ); //下面這種使用方式,在調用時Dyna
新聞熱點
疑難解答