C# 如何获取调用方法的参数值?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/492600/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 05:31:19  来源:igfitidea点击:

How can I get the values of the parameters of a calling method?

c#reflectiondynamic

提问by Chris Benard

Question

I'm writing some code that needs to be able to get the valuesof the parameters from the method that called into the class. I know how to get all the way to the ParameterInfo[] array, but I don't know how to then get the values. Is this even possible?

我正在编写一些代码,需要能够从调用类的方法中获取参数的。我知道如何获得 ParameterInfo[] 数组,但我不知道如何获得这些值。这甚至可能吗?

If it is, I think it has something to do with using the MethodBody property from the MethodInfo object, which allows you to inspect the IL stream, including properties, but I don't know how to do it, and I haven't found applicable code on Google.

如果是,我认为它与使用 MethodInfo 对象中的 MethodBody 属性有关,该属性允许您检查 IL 流,包括属性,但我不知道该怎么做,而且我还没有找到适用于 Google 的代码。

Code

代码

// 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");
            }
        }
    }
}

采纳答案by ShuggyCoUk

You cannot do it without introspecting the stack yourself (and this is fragile since many optimizations may mean the stack frame is not what you expect, or even that the parameter passed is not in fact what the method signature would suggest (it is perfectly possible for an optimizing JIT compiler to spot that you are only using a sub field of an object/struct and pass that instead).

如果不自己反省堆栈,您就无法做到这一点(这很脆弱,因为许多优化可能意味着堆栈帧不是您所期望的,甚至传递的参数实际上也不是方法签名所建议的(这完全有可能一个优化的 JIT 编译器,以发现您仅使用对象/结构的子字段并传递它)。

The ParameterInfo simply tells you the signatureof the method as compiled, not the values that were passed.

ParameterInfo 只是告诉您编译时方法的签名,而不是传递的值。

The only realistic way to achieve this automatically is via code injection (via something like AOP) to create the data and do what you want with it based on analysing the IL.

自动实现这一点的唯一现实方法是通过代码注入(通过 AOP 之类的东西)来创建数据并根据分析 IL 用它做你想做的事情。

This is generally not a good idea, if you need to debug something use a debugger, if you need to log something be explicit about what you are logging.

这通常不是一个好主意,如果您需要调试某些内容,请使用调试器,如果您需要记录某些内容,请明确说明您正在记录的内容。

To be clear simple reflective techniques cannotachieve what you desire with full generality

要清楚,简单的反射技术不能完全通用地实现您的愿望

回答by Anton Gogolev

You can't do it with either StackFrame or StackTrace. You can, however, employ some interception framework (such as AOP stuff from Spring.NET) so that you can get hold of parameter values.

你不能用 StackFrame 或 StackTrace 做到这一点。但是,您可以使用一些拦截框架(例如 Spring.NET 中的 AOP 内容),以便您可以获取参数值。

回答by Chris Benard

Jonathan Keljo at Microsoft says, in this news group post, :

微软的 Jonathan Keljo 在这个新闻组帖子中说:

Unfortunately, the only easy way to get argument information from a callstack today is with a debugger. If you're trying to do this as part of error logging in an application and you plan to send the error log back to your support department, we're hoping to have you use minidumps for that purpose in the future. (Today, using a minidump with managed code is a little problematic as it does not include enough information to even get a stack trace by default. A minidump with heap is better, but not so "mini" if you know what I mean.)

A purist would say that allowing people to write code that can get arguments from functions elsewhere on the callstack would encourage them to break encapsulation and create code that's very fragile in the face of change. (Your scenario does not have this particular problem, but I've heard other requests for this feature that would. Anyway most of those requests can be solved in other ways, like using thread stores.) However, more importantly there would be security implications of this--applications that allow plugins would be at risk of those plugins scraping the stack for sensitive information. We could certainly mark the function as requiring full-trust, but that would make it unusable for pretty much every scenario I've heard of.

Jonathan

不幸的是,今天从调用堆栈中获取参数信息的唯一简单方法是使用调试器。如果您尝试将其作为应用程序错误日志记录的一部分并计划将错误日志发送回您的支持部门,我们希望您将来可以为此目的使用小型转储。(今天,使用带有托管代码的小型转储有点问题,因为它不包含足够的信息甚至默认情况下获取堆栈跟踪。带有堆的小型转储更好,但如果您知道我的意思,那就不是那么“迷你”了。)

一个纯粹主义者会说,允许人们编写可以从调用堆栈上其他地方的函数获取参数的代码会鼓励他们打破封装并创建在面对变化时非常脆弱的代码。(你的场景没有这个特殊的问题,但我听说过这个功能的其他请求。无论如何,这些请求中的大多数可以通过其他方式解决,比如使用线程存储。)但是,更重要的是会有安全隐患其中——允许插件的应用程序将面临这些插件抓取堆栈以获取敏感信息的风险。我们当然可以将该功能标记为需要完全信任,但这将使其在我听说过的几乎所有场景中都无法使用。

乔纳森

So... I guess the short answer is "I can't." That sucks.

所以......我想简短的回答是“我不能。” 那太糟糕了。

回答by BFree

See here:

看这里:

Can you get a list of variables on the stack in C#?

你能在 C# 中获得堆栈上的变量列表吗?

I don't think it's possbile, based on all the comments on my answer there. The PropertyInfo class does have a GetValue method, but that requires you to have an actual object of which you want to get the value from.

根据我在那里回答的所有评论,我认为这不可能。PropertyInfo 类确实有一个 GetValue 方法,但这需要您拥有一个要从中获取值的实际对象。

回答by Daniel Crenna

Yes, you can do this.

是的,你可以这样做。

What you need to do is use an IL disassembler (which is achievable within the System.Reflection.Emit namespace) to find the Operand that contains the parameter value you're looking for.

您需要做的是使用 IL 反汇编程序(可在 System.Reflection.Emit 命名空间内实现)来查找包含您要查找的参数值的操作数。

Start with this SO question: C# reflection and finding all references

从这个 SO 问题开始:C# 反射并找到所有引用

Then use the class mentioned in the answers (from Mono.Reflection) to do your inspection. Something like this:

然后使用答案中提到的类(来自 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...
                }
            }