如何枚举传递的方法参数

可以枚举被调用的方法参数类型/信息,如下所示:

private void SomeMethod(int thisValue, string thatValue) { StackTrace stackTrace = new StackTrace(); foreach (ParameterInfo pInfo in stackTrace.GetFrame(0).GetMethod().GetParameters()) { string name = pInfo.Name; string type = pInfo.GetType().ToString(); } } 

但有没有办法获得每个参数的实际对象?

编辑 :我的目标是枚举所有参数并获取它们的值。 使用LinQ表达式,可以获得如下参数值:

 private void SomeMethod(int thisValue, string thatValue) { object valueOfThis = GetParameterValue(() => thisValue); object valueOfThat = GetParameterValue(() => thatValue); } private object GetParameterValue(Expression<Func> expr) { var body = ((MemberExpression)expr.Body); return ((FieldInfo)body.Member).GetValue(((ConstantExpression)body.Expression).Value); } 

但我想做的是:

 foreach (fooObject o in thisMethod.GetParameterObjects()) { object someValue = GetParameterValue(() => fooObject); } 

从而有一个收集所有参数及其值的通用方法。

更新:

通过尝试解释所有内容,我看起来“过于复杂”了最初的答案。 这是答案的简短版本。

 private static void SomeMethod(int thisValue, string thatValue) { IEnumerable parameters = GetParameters(() => SomeMethod(thisValue, thatValue)); foreach (var p in parameters) Console.WriteLine(p); } private static IEnumerable GetParameters(Expression expr) { var body = (MethodCallExpression)expr.Body; foreach (MemberExpression a in body.Arguments) { var test = ((FieldInfo)a.Member).GetValue(((ConstantExpression)a.Expression).Value); yield return test; } } 

这是长版本,有一些解释。

实际上,如果使用表达式树,则不需要在方法内部枚举其参数。

  static void Main(string[] args) { // First approach. IEnumerable parameters = GetParametersFromConstants(() => SomeMethod(0, "zero")); foreach (var p in parameters) Console.WriteLine(p); // Second approach. int thisValue = 0; string thatValue = "zero"; IEnumerable parameters2 = GetParametersFromVariables(() => SomeMethod(thisValue, thatValue)); foreach (var p in parameters2) Console.WriteLine(p); Console.ReadLine(); } private static void SomeMethod(int thisValue, string thatValue) { Console.WriteLine(thisValue + " " + thatValue); } private static IEnumerable GetParametersFromVariables(Expression expr) { var body = (MethodCallExpression)expr.Body; foreach (MemberExpression a in body.Arguments) { var test = ((FieldInfo)a.Member).GetValue(((ConstantExpression)a.Expression).Value); yield return test; } } private static IEnumerable GetParametersFromConstants(Expression expr) { var body = (MethodCallExpression)expr.Body; foreach (ConstantExpression a in body.Arguments) { var test = a.Value; yield return test; } } } 

请注意,如果使用表达式树,则代码很大程度上取决于传递给方法的表达式。 我已经展示了一个使用常量,一个使用变量。 但当然可以有更多场景。 您可以重构此代码以针对这两种情况使用单个方法,但我认为这样可以更好地说明问题。

好的,所以这是交易。

你不能这样做,而不是托管语言。 我没有看到有人会让你控制堆栈帧。 在某种程度上,这就是你想要的。 因为您需要获取值的信息。

现在运行时知道这一点,它拥有所有信息,但你无法对如何创建堆栈框架做出假设,因为你并不打算这样做。

因此,只有一种方法可以解决这个问题。 分析API。

我结束了。 在分析API的function内。 我敢打赌有一种方法可以让你通过从托管代码调用非托管类来深入了解参数值。

现在,我不会这样做,因为那里已经有很好的分析工具,JetBrains dotTrace来命名一个和VS2010中的IntelliTrace所有这些令人头疼的事情将会消失…… IntelliTrace将让你做时间调试。

实现这一目标的另一个显而易见的方法是完全foobar,但最终可能会有趣的尝试,它总是可以这样做,但我永远不会在生活中把这些代码放在生产环境中。

 // compile with unsafe unsafe { var p = stackalloc int[1]; var baseAddr = p - sizeof(int); } 

现在,您无法写入baseAddr但应该允许您阅读它。 棘手的部分是理解堆栈帧,并且必须符合调用约定,并且必须确定一定的时间。 这是一个很糟糕的东西,它是快速调用。

有了这些信息和ParameterInfo对象,您应该能够遍历参数。

既然你将使用原始指针,你需要将它们变成托管对象,并且有一个类 。

你去吧,疯了!

但是一个很大的警告 ,当你走上堆栈时你会发现什么,不会是你所期望的。 因为参数可以放在寄存器中,所以无法从托管代码中访问寄存器。

您可以使用MethodInfo.GetCurrentMethod().GetParameters()来获取方法参数列表。 但是通过反思来获取他们的价值是不可能的。