【问题标题】:Get names of parameters in method (and use as Dictionary keys?)获取方法中的参数名称(并用作字典键?)
【发布时间】:2012-11-10 06:18:51
【问题描述】:

我正在编写一个审计日志系统,以集成到现有的软件中,并且数据库结构包含一个字段,用于记录有关正在记录的操作的详细信息。不必花哨;它不需要太多,当它需要时,在大多数情况下,开发人员会读取它以找出调用了哪个方法以及使用了哪些参数,诸如此类。这意味着虽然它可能应该是人类可读的,但它不需要被任何东西解析。因此,与其有很多重载,或者使用可怕的 switch case 字符串替换,我想一个写细节 blob 的好方法是进行日志调用,以获取正在记录的操作所需的参数的名称,以及值传递给他们的。我进行了一些研究,并在反射方法中发现了一些有希望的东西,但我还没有找到任何可以清楚地解释如何做到这一点的东西。

这是我所追求的粗略模拟:

Dictionary<string,string> parameters = new Dictionary<string,string>();
foreach (Parameter p in MethodCall)
{
    parameters.Add(p.Name, p.Value.ToString());
}

LogEvent(EventType.Something, userID = thisUser, details = parameters);

我知道它在实践中可能比这更复杂,但它为您提供了总体思路。在我的 LogEvent 方法中,有一些东西可以添加时间戳,为用户端日志查看器构建描述性句子(技术细节比我们向管理员和开发人员展示的要少,以免暴露我们的程序/数据库结构)和 - 理论上 - 构建参数详细信息字典中的某种 blob(可能是 JSON 或类似的)。

【问题讨论】:

    标签: c# reflection


    【解决方案1】:

    相关的是:Obtain parameter values from a stack frame in .NET? 有一些有用的答案。

    您想要记录方法名称和参数列表。方法名称使用 StackFrame 很容易,但我认为您不能使用简单的反射来获取参数值。

    【讨论】:

      【解决方案2】:

      如果您的日志记录方法采用表达式参数,则可以通过此代码获取参数名称和值:

      static void LogSomething(Expression<Action> expression)
      {
          var methodCallExpression = ((MethodCallExpression) expression.Body);
          var parameterNames = methodCallExpression.Method.GetParameters().Select(p => p.Name);
          var values = methodCallExpression.Arguments.Select(a => a.Value);
      }
      

      【讨论】:

      • 看起来很有希望。你知道这个开销是多少吗?由于这是一种日志记录方法,它将被添加到许多地方的软件中,我不希望它太慢。在这里多花半秒左右就可以了,但如果整个事情开始永远持续下去,那么我将不得不找到另一种方法来做到这一点。
      • @anaximander,无需调用方法或获取属性值的反射,字段工作速度很快。从表达式树中获取参数值也很快。所以我认为这将花费不到半秒的时间:)
      • 优秀。谢谢您的帮助!我会试试这个。
      【解决方案3】:

      我会使用拦截器 (Castle.DynamicProxy),如下例所示:

        internal class Program
        {
          private static void Main(string[] args)
          {
      
            var interceptor = new Interceptor();
            var businessObjectClass = new ProxyGenerator().CreateInterfaceProxyWithoutTarget<IBusinessObjectClass>(interceptor);
      
            businessObjectClass.Method3("what",123);
      
            Console.ReadLine();
          }
        }
      
        public class Interceptor : IInterceptor
        {
          #region IInterceptor Members
      
          public void Intercept(IInvocation invocation)
          {
            Console.WriteLine(string.Format("Intercepted call to: " + invocation.Method.Name));
            foreach (var argument in invocation.Arguments)
            {
              Console.WriteLine(string.Format("\t Param: " + argument.ToString()));
            }
            invocation.Proceed();
          }
      
          #endregion
        }
      
        public interface IBusinessObjectClass
        {
          void Method3(string stringValue, int intValue);
        }
      
        public class BusinessObjectClass : IBusinessObjectClass
        {
      
           public void Method3(string stringValue, int intValue)
          {
            return;
           }
      
        }
      

      DynamicProxy

      【讨论】:

      • 有趣...所以这会拦截方法调用?这可能值得研究;如果人们不必显式调用日志记录,那就太好了。话虽如此,我不需要记录每个方法调用,因此需要一些逻辑来决定记录什么......不过值得研究。
      • 是的,这会拦截所有实现被代理接口的方法调用。
      【解决方案4】:

      你为什么不试试PostSharp?它旨在解决像您这样的问题。在示例中,您会发现打印参数值的logging 方面。结合 XML 配置,将允许管理员/用户随意启用日志记录/跟踪。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-10-01
        • 2011-10-09
        • 2016-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-16
        • 1970-01-01
        相关资源
        最近更新 更多