C# 有并没有办法获得传递给方法的参数数组?

C# 有并没有办法获得传递给方法的参数数组?,c#,reflection,methods,arguments,C#,Reflection,Methods,Arguments,假设我有一个方法: public void SomeMethod(String p1, String p2, int p3) { #if DEBUG object[] args = GetArguments(); LogParamaters(args); #endif // Do Normal stuff in the method } public void SomeMethod(String p1, String p2, int p3) {

假设我有一个方法:

 public void SomeMethod(String p1, String p2, int p3)
 {

 #if DEBUG
    object[] args = GetArguments();
    LogParamaters(args);
 #endif

     // Do Normal stuff in the method
 }
 public void SomeMethod(String p1, String p2, int p3) 
 { 

 #if DEBUG 
    LogParamaters(p1, p2, p3); 
 #endif 

     // Do Normal stuff in the method 
 } 
是否有方法检索传递到方法中的参数数组,以便记录这些参数

我有很多方法,希望避免手动将参数按名称传递给记录器,因为人为错误将不可避免地潜入

我猜它将涉及某种形式的反射——这很好,因为它只用于调试目的

更新

更多信息:

我无法更改SomeMethod的方法签名,因为它作为WebMethod公开,并且必须复制它正在模拟的遗留系统

旧系统已记录传入的参数。首先,新的实现将包装遗留系统,因此我希望将参数记录到C#版本中,以便验证是否以正确的顺序传递了正确的参数


我只是想记录参数值和顺序,而不是它们的名称。

动态类型系统有一些功能可以做到这一点,但是您的类需要继承动态基类。

如果您只想传递值,您可以欺骗并定义一个对象数组:

public static void LogParameters(params object[] vals)
{

}
但是,这将导致对值类型进行装箱,也不会给您任何参数名称

假设我有一个方法:

 public void SomeMethod(String p1, String p2, int p3)
 {

 #if DEBUG
    object[] args = GetArguments();
    LogParamaters(args);
 #endif

     // Do Normal stuff in the method
 }
 public void SomeMethod(String p1, String p2, int p3) 
 { 

 #if DEBUG 
    LogParamaters(p1, p2, p3); 
 #endif 

     // Do Normal stuff in the method 
 } 
更新:不幸的是,反射不会自动为您完成所有操作。您需要提供值,但可以使用反射来提供参数名称/类型:

因此,方法sig将更改为:

public static void LogParameters(string[] methodNames, params object[] vals)
{ }

然后,您可以强制/假设每个集合中的每个索引都符合要求,以便
methodNames[0]
具有值
vals[0]

,如果使用,您只需向要记录的方法添加一个属性即可。在这个属性中,您可以编写日志代码,还可以提供所需的参数。这就是所谓的横切关注点和AOP(面向方面编程)

很好地帮助了日志调用,但对现有的方法签名没有帮助。使用日志记录可能是一种更有效的方法?

我不确定访问调用堆栈的API是否提供了获取参数列表的方法

但是,有一些方法可以注入IL来拦截方法调用并执行自定义代码

我经常使用的库是Gael Fraiteur提供的,它包括一个应用程序,该应用程序运行后期构建,并根据您使用的方面在输出程序集中注入IL。有一些属性可以用来修饰程序集、类型或单个方法。例如:

[Serializable]
public sealed class LoggingAttribute : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs eventArgs)
    {
        Console.WriteLine("Entering {0} {1} {2}",
                          eventArgs.Method.ReflectedType.Name,
                          eventArgs.Method,
                          string.Join(", ", eventArgs.Arguments.ToArray()));

        eventArgs.MethodExecutionTag = DateTime.Now.Ticks;
    }

    public override void OnExit(MethodExecutionArgs eventArgs)
    {
        long elapsedTicks = DateTime.Now.Ticks - (long) eventArgs.MethodExecutionTag;
        TimeSpan ts = TimeSpan.FromTicks(elapsedTicks);

        Console.WriteLine("Leaving {0} {1} after {2}ms",
                          eventArgs.Method.ReflectedType.Name,
                          eventArgs.Method,
                          ts.TotalMilliseconds);
    }
}
在此之后,您可以使用此属性装饰所需的方法:

[Logging]
public void SomeMethod(String p1, String p2, int p3) 
{
   //..
}

在某些情况下可能不起作用,但应该让您开始:)


只要知道预期的类型,就可以将它们记录到SQL数据库中。编写一个执行类型检查的方法,然后用参数(参数)值填充相应的DB列。如果您有一个自定义类型,那么您可以使用类型名称并将其保存为字符串,保存在它自己的特殊列中

-编辑

另外,使用
MethodBase.Name
扩展方法,您可以将参数与将其作为参数的方法相关联,如下面另一篇文章中所述。这是一种跟踪所使用的所有方法、使用哪些参数以及使用哪种类型的简便方法


这是个好主意吗?:)

以下是我提出的解决方案:

PostSharp或其他AOP解决方案在这种情况下并不实际,所以不幸的是,我不得不放弃这个想法

虽然可以使用反射来访问参数名和类型,但访问运行时值的唯一方法是附加调试器

有关更多信息,请参见此处:

因此,这仍然给我留下了大约50种方法的问题,这些方法需要手工添加日志记录

对救援的反思

public String GetMethodParameterArray()
    {
        var output = new StringBuilder();
        output.AppendLine();

        Type t = typeof(API);
        foreach (var mi in t.GetMethods())
        {
                var argsLine = new StringBuilder();
                bool isFirst = true;
                argsLine.Append("object[] args = {");
                var args = mi.GetParameters();

                foreach (var pi in args)
                {
                    if (isFirst)
                    {
                        isFirst = false;
                    }
                    else
                    {
                        argsLine.Append(", ");
                    }
                    argsLine.AppendFormat("{0}", pi.Name);
                }
                argsLine.AppendLine("};"); //close object[] initialiser

                output.AppendLine(argsLine.ToString());
                output.AppendFormat("Log(\"{0}\",args);", mi.Name);
                output.AppendLine();
                output.AppendLine();
            }
        return output.ToString();
    }
此代码段循环遍历类上的方法,并输出一个使用传入该方法的参数初始化的object[]数组和一个包含参数和方法名称的日志调用

示例输出:

object[] args = {username, password, name, startDate, endDate, cost};
Log("GetAwesomeData",args);
然后可以将该块粘贴到方法的顶部,以达到所需的效果


它比我希望的更为手动,但它比手工输入参数要好得多,而且更不容易出错。

当然可以……查看这篇文章,它可以获得参数的实际值。

你读过这个问题吗?他希望记录进入函数的所有参数,并希望访问该数据;其中GetMethodParams()将返回paramaters数组。我不太在意拳击的开销我已经修改了我的答案,但是,正如其他人所说,有一些框架可以作为编译器步骤附加必要的代码,这意味着您不需要手动编写大部分代码。当然,PostSharp的唯一缺点是它不是免费的,您仍然需要编辑代码来放置属性。关于参数的哪些信息存储在日志中?类型、名称、值?这意味着您真正谈论的是参数,而不是参数@斯塔克斯,是的,区别是有意义的。我正在寻找传递到方法中的参数值。+1。我本来打算写一些关于编译器自动重新编写CIL输出以添加日志记录的内容,但仅仅使用一个已建立的产品可能会更容易。同时,使用它执行上述操作非常快速和容易。代码示例?否则就有点“只链接”了。(
System.Diagnostics.StackTrace
/
System.Diagnostics.StackFrame
似乎只提供源文件名和行号信息等,而不是实际的