我有一个问题一直困扰着我。如何在执行期间(完成之前)检索在执行表达式树时创建的变量的运行时值?当然,您可以根据Lambda变量中最后一个表达式的返回类型获取最终值,但我有兴趣在执行过程中获取实际变量值。
下面我创建了一个For循环的简单示例,我尝试输出以控制格式化字符串。对于此上下文,假设我不能简单地在此sub之外设置某些引用类的属性。我只想获得lambda执行中隐藏的值。
public static void WriteConsoleLineTemp(string Text, object obj1, object obj2)
{
Console.WriteLine(Text, obj1.ToString(), obj2.ToString());
}
private void TempSub()
{
LabelTarget label1 = Expression.Label();
ParameterExpression IteratorInt = Expression.Variable(typeof(int), "i");
ParameterExpression TempInteger = Expression.Variable(typeof(int), "int");
ParameterExpression TempRandom = Expression.Variable(typeof(Random), "rand");
MethodInfo ToStringMethod = typeof(object).GetMethod("ToString", Type.EmptyTypes);
MethodInfo ConsoleWriteLine1 = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(object) });
MethodInfo ConsoleWriteLine2 = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string), typeof(object[]) });
MethodInfo ConsoleWriteLine3 = typeof(Form1).GetMethod("WriteConsoleLineTemp", new Type[] { typeof(string), typeof(int), typeof(int) });
BlockExpression SuperTemp = Expression.Block(new[] { IteratorInt, TempInteger, TempRandom },
Expression.Assign(TempRandom, Expression.Constant(new Random())),
Expression.Loop(
Expression.Condition(Expression.GreaterThanOrEqual(IteratorInt, Expression.Constant(5)),
Expression.Return(label1),
Expression.Block(
Expression.AddAssign(IteratorInt, Expression.Constant(1)),
Expression.Assign(TempInteger, Expression.Call(TempRandom, typeof(Random).GetMethod("Next", new Type[] { typeof(int), typeof(int) }), Expression.Constant(0), Expression.Constant(10))),
//Expression.Call(null, ConsoleWriteLine1, Expression.Call(IteratorInt, ToStringMethod)), // This Works but only without format paramaters
//Expression.Call(null, ConsoleWriteLine1, Expression.Call(TempInteger, ToStringMethod)), //This Works but only without format paramaters
Expression.Call(null, ConsoleWriteLine2, Expression.Constant("Iteration {0}, Value = {1}"), Expression.Constant(new object[] { IteratorInt, TempInteger })),
Expression.Call(null, ConsoleWriteLine2, Expression.Constant("Iteration {0}, Value = {1}"), Expression.Constant(new object[] { Expression.Call(IteratorInt, ToStringMethod), Expression.Call(TempInteger, ToStringMethod) })),
Expression.Call(null, ConsoleWriteLine3, Expression.Constant("Iteration {0}, Value = {1}"), Expression.TypeAs(IteratorInt, typeof(object)), Expression.TypeAs(TempInteger, typeof(object))) // Works, but requires a specific sub
)
),
label1)
);
Action MyExecutor = (Action)Expression.Lambda(SuperTemp).Compile();
MyExecutor();
}
输出:
Iteration i, Value = int
Iteration i.ToString(), Value = int.ToString()
Iteration 1, Value = 6
Iteration i, Value = int
Iteration i.ToString(), Value = int.ToString()
Iteration 2, Value = 8
Iteration i, Value = int
Iteration i.ToString(), Value = int.ToString()
Iteration 3, Value = 1
Iteration i, Value = int
Iteration i.ToString(), Value = int.ToString()
Iteration 4, Value = 8
Iteration i, Value = int
Iteration i.ToString(), Value = int.ToString()
Iteration 5, Value = 0
第三个Call表达式输出正确的结果,但需要一个特定的子句(输出显示在每三行)。三个Call表达式中的第一个接近我想要的。最终,如果我可以使用类似的东西,那就太好了。
Expression.VariableValue(TempInteger)
其中输出是object类型,然后可以自由地进行类型转换,这样我就能做到:
Expression.Call(null, ConsoleWriteLine1, Expression.Constant("Iteration " + Expression.VariableValue(IteratorInt).ToString() + ", Value = " + Expression.VariableValue(TempInteger).ToString()));
这只是一个简单的例子。其他相关问题包括输出具有特定类型异常的Catch块的结果,其中可以正确访问和类型化异常值,而不是仅为打印出异常信息创建新子。
有没有办法简单地检索运行时值?
答案 0 :(得分:1)
如果要获取变量的值,只需使用代表变量的ParameterExpression
即可。如果您想使用Console.WriteLine(string, object, object)
重载,那么唯一的问题是您需要从int
转换为object
(C#隐式执行):
MethodInfo ConsoleWriteLine3 = typeof(Console).GetMethod(
"WriteLine", new Type[] { typeof(string), typeof(object), typeof(object) });
…
Expression.Call(
null, ConsoleWriteLine3,
Expression.Constant("Iteration {0}, Value = {1}"),
Expression.Convert(IteratorInt, typeof(object)),
Expression.Convert(TempInteger, typeof(object)))
如果你想使用Console.WriteLine(string, object[])
重载,你还需要创建params
数组(C#也适合你):
Expression.Call(
null, ConsoleWriteLine2,
Expression.Constant("Iteration {0}, Value = {1}"),
Expression.NewArrayInit(
typeof(object),
Expression.Convert(IteratorInt, typeof(object)),
Expression.Convert(TempInteger, typeof(object))))