【问题标题】:How to get the parameter values from previous method call in C#? [duplicate]如何从 C# 中的先前方法调用中获取参数值? [复制]
【发布时间】:2012-04-22 04:29:25
【问题描述】:

这个问题和我之前的问题有关How to get a IDictionary<string, object> of the parameters previous method called in C#?。我写了代码,但仍然缺少一块。如何从参数中获取值?

如果执行以下代码,则输出只显示参数的名称,而不显示值。

using System;
using System.Collections.Generic;
using System.Diagnostics;

namespace Question {
    internal class Program {
        public static void Main(string[] args) {
            var impl = new Implementation();
            var otherClass = new OtherClass { Name = "John", Age = 100 };
            impl.MethodA(1, "two", otherClass);
        }
    }

    internal class Implementation {
        public void MethodA(int param1, string param2, OtherClass param3) {
            Logger.LogParameters();
        }
    }

    internal class OtherClass {
        public string Name { get; set; }
        public int Age { get; set; }
    }

    internal class Logger {
        public static void LogParameters() {
            var parameters = GetParametersFromPreviousMethodCall();
            foreach (var keyValuePair in parameters)
                Console.WriteLine(keyValuePair.Key + "=" + keyValuePair.Value);
        }

        private static IDictionary<string, object> GetParametersFromPreviousMethodCall() {
            var stackTrace = new StackTrace();
            var frame = stackTrace.GetFrame(2);
            var method = frame.GetMethod();

            var dictionary = new Dictionary<string, object>();
            foreach (var parameterInfo in method.GetParameters())
                dictionary.Add(parameterInfo.Name, parameterInfo.DefaultValue);
            return dictionary;
        }
    }
}

【问题讨论】:

  • 同一个问题不要问两次。
  • 其实是2个问题。一种用于获取 ParameterInfo,另一种用于获取 Parameter 值。这些问题使用相同的示例,但它们不相关。

标签: c# .net reflection


【解决方案1】:

您的代码可能是死胡同。堆栈帧中没有任何内容可以让您获取参数值。

但是,完全可以执行此任务。您想要的与编写分析器非常相似。您可能希望将代码注入任何您想要记录的方法中以向量化其参数。假设您从这样的课程开始:

public class ParameterBlob {
    public ParameterInfo Info { get; set; }
    public object Value { get; set; }
}

假设你有一个这样的方法:

public static void LogMethodCall(MethodInfo method, param ParameterBlob[] parameterBlobs) { /* ... */ }

这里或多或少是您要注入的内容:

MethodInfo methodInfo = MyLogging.GetMyMethodInfo();
ParameterBlob[] blobs = new ParameterBlobs[MyLogging.GetMyParameterCount(methodInfo);
ParameterBlob blob = new ParameterBlob();
blob.Info = MyLogging.GetParameterInfo(methodInfo, 0);
blob.Value = param0; // More on this
blobs[0] = blob;
blob = new ParameterBlob();
blob.Info = MyLogging.GetParameterInfo(methodInfo, 1);
blob.Value = param1; // More on this
blobs[1] = blob;
// ...
blob = new ParameterBlob();
blob.Info = MyLogging.GetParameterInfo(methodInfo, n);
blob.Value = paramn; // more on this
blobs[n] = blob;
MyLogging.LogMethodCall(methodInfo, blobs);

所以那些说“更多关于这个”的行?你实际上不能写它们。但是您可以编写一个示例例程来引用它自己的参数来执行此操作。您拥有的是ldarg 指令和stloc 指令(以及介于两者之间的其他一些指令)。关键是,用 C# 编写它,然后使用编译器和 ILDASM 向您显示一个参数所需的正确代码,然后您可以编写一个例程来为您生成 CIL,然后您将插入进入 .NET 分析 API 以附加到您想要的任何例程。

有关更多信息,请参阅文章 Rewrite MSIL Code on the Fly with the .NET Framework Profiling API

您可能还想使用属性将方法标记为可记录或不可记录。

唯一的问题是您必须具有运行时访问权限才能执行此操作,而您可能没有。你完全不走运吗?没有。

通过使用Cecil,您可以在整个程序集运行之前访问它并对其进行预处理,以便为您注入日志记录调用。 Cecil 非常简单,重写任何程序集以包含日志调用应该需要几天的时间。如果您可以先验地知道您正在目标程序集中执行此操作并且已经设置了适当的引用,则更少。本质上,您将访问程序集中的每个方法,如果它是可记录的,您将注入 CIL 以记录其所有参数,就像上面的示例一样。

【讨论】:

    【解决方案2】:

    根据之前的问题 (How can I get the values of the parameters of a calling method?),无法通过 StackTrace。

    AOP 是你的朋友。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-11
      • 1970-01-01
      • 2021-11-27
      • 2010-10-04
      • 2014-08-26
      相关资源
      最近更新 更多