我正在编写一些代码,这些代码需要能够从调用类的方法中获取参数的值。我知道如何一直到ParameterInfo []数组,但我不知道如何获取值。这甚至可能吗?
如果是,我认为它与使用MethodInfo对象中的MethodBody属性有关,它允许您检查IL流,包括属性,但我不知道如何做,而且我没有在Google上找不到适用的代码。
// Finds calling method from class that called into this one
public class SomeClass
{
public static void FindMethod()
{
for (int i = 1; i < frameCount; i++)
{
var frame = new StackFrame(i);
var methodInfo = frame.GetMethod();
if (methodInfo.DeclaringType != this.GetType())
{
string methodName = frame.GetMethod().Name;
var paramInfos = methodInfo.GetParameters();
// Now what?? How do I get the values from the paramInfos
break;
}
else if (i == frameCount - 1)
{
throw new TransportException("Couldn't find method name");
}
}
}
}
答案 0 :(得分:17)
如果不自己反省堆栈就不能这样做(这很脆弱,因为许多优化可能意味着堆栈帧不是你所期望的,或者甚至传递的参数实际上不是方法签名所暗示的(它是完美的JIT编译器可以发现你只使用了一个对象/结构的子字段而是传递了它。)
ParameterInfo只是告诉您编译方法的签名,而不是传递的值。
自动实现此目的的唯一现实方法是通过代码注入(通过类似AOP之类的东西)来创建数据,并根据分析IL执行您想要的操作。
这通常不是一个好主意,如果你需要使用调试器来调试某些东西,如果你需要记录一些关于你正在记录的内容。
要明确简单的反思技巧不能以完全的普遍性实现您的愿望
答案 1 :(得分:5)
微软的Jonathan Keljo在this news group post中说:
不幸的是,从a获取参数信息的唯一简单方法 今天的callstack是一个调试器。如果你试图这样做的一部分 错误登录应用程序并计划将错误日志发送回 你的支持部门,我们希望你能使用minidumps 未来的目的。 (今天,使用托管代码的minidump是一个 这个问题很少,因为它不包含足够的信息来获得一个 默认情况下堆栈跟踪。带堆的minidump更好,但不是那么“迷你” 如果你知道我的意思。)
纯粹主义者会说允许人们编写可以获得的代码 来自callstack其他地方的函数的参数会鼓励他们 打破封装并创建面对非常脆弱的代码 更改。 (你的情况没有这个特殊的问题,但我已经 听说过这个功能的其他要求。无论如何大多数 请求可以通过其他方式解决,例如使用线程存储。)但是, 更重要的是,这会对安全性产生影响 - 应用程序 允许插件存在那些插件刮掉堆栈的风险 敏感的信息。我们当然可以将该功能标记为要求 完全信任,但这会使它几乎无法用于所有场景 我听说过。
Jonathan
所以...我想简短的回答是“我不能。”太糟糕了。
答案 2 :(得分:4)
是的,你可以这样做。
您需要做的是使用IL反汇编程序(可在System.Reflection.Emit命名空间中实现)来查找包含您正在查找的参数值的操作数。
从这个问题开始:C# reflection and finding all references
然后使用答案中提到的类(来自Mono.Reflection)进行检查。像这样:
var instructions = method.GetInstructions();
foreach (var instruction in instructions)
{
var methodInfo = instruction.Operand as MethodInfo;
if(methodInfo == null)
{
continue;
}
if (instruction.OpCode.Name.Equals("call") && methodInfo.Name.Equals("YourMethodHere"))
{
var value = (CastToMyType)instruction.Previous.Operand;
// Now you have the value...
}
}
答案 3 :(得分:1)
您无法使用StackFrame或StackTrace执行此操作。但是,您可以使用一些拦截框架(例如Spring.NET中的AOP),以便您可以获取参数值。
答案 4 :(得分:0)
见这里:
Can you get a list of variables on the stack in C#?
根据对我的回答的所有评论,我不认为这是可能的。 PropertyInfo类有一个GetValue方法,但是这需要你有一个你想从中获取值的实际对象。
答案 5 :(得分:0)
不确定这是否可以作为解决方案,但可以用于我遇到的特定情况, 我想在每次代码修改最少的情况下修改一次浮动记录,
在堆栈跟踪行上读取文件以找出参数
public static Score operator +(Score x,float y) {
var st = new StackTrace(true);
var sf = st.GetFrame(1);
string paramName = File.ReadLines(sf.GetFileName()).ElementAtOrDefault(sf.GetFileLineNumber()-1).Split(new[] { "+=" }, StringSplitOptions.None)[1];
x.DebugString += (paramName+" "+y);
x.DebugString += System.Environment.NewLine;
x.val += y;
return x;
}
void Main(){
Score score = new Score();
float firstScore = 2;
float secondScore = -13;
score+=firstScore;
score+=secondScore;
Console.WriteLine(score.DebugString);
}
Output :
firstscore 2
secondScore -13