我有一個問題,一直困擾我一段時間。如何檢索在執行期間(在完成之前)執行表達式樹時創建的變量的運行時值?當然,你可以根據Lambda變量中最後一個表達式的返回類型來獲得最終值,但我有興趣在執行過程中獲取實際變量值。如何在表達式樹中獲取變量的值
下面我創建了一個For循環的簡單例子,我試圖輸出到控制格式化的字符串。對於這個上下文,假設我不能簡單地在這個子外面設置一些被引用的類的屬性。我只是希望獲得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表達式中的第一個接近我的意願。最終,這將是很好,如果我可以使用類似:
Expression.VariableValue(TempInteger)
,其中輸出類型的對象,然後可以自由類型強制轉換和這樣的,所以我將能夠做到:
Expression.Call(null, ConsoleWriteLine1, Expression.Constant("Iteration " + Expression.VariableValue(IteratorInt).ToString() + ", Value = " + Expression.VariableValue(TempInteger).ToString()));
這只是一個簡單的例子。其他相關問題包括輸出具有特定類型異常的Catch塊的結果,其中Exception的值可以被適當地訪問和進行類型化,而不是創建僅用於打印Exception info的新子。
有什麼方法可以簡單地檢索運行時間值嗎?
我不確定你的意思。在編譯表達式之後,您有一個常規方法。原始表達式對象與該方法無關;如果它們是,那麼在你編譯表達式兩次或更多次之後,檢查其中一個對象意味着什麼?它們涉及哪種方法?因此,鑑於編譯後的表達式只是一個常規方法,您的問題似乎歸結爲「如何知道方法執行時方法中的局部變量具有什麼值」。對此的答案是,「除非方法傳遞給你,否則你不這樣做」。 – 2015-03-31 03:55:15