说我有方法:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
object[] args = GetArguments();
LogParamaters(args);
#endif
// Do Normal stuff in the method
}
有没有办法检索传递给方法的参数数组,以便记录它们?
我有很多方法,并希望避免手动将参数按名称传递给记录器,因为人为错误将不可避免地蔓延。
我猜它会以某种形式涉及反射 - 这很好,因为它只会用于调试目的。
更新
更多信息:
我无法更改SomeMethod的方法签名,因为它是作为WebMethod公开的,并且必须复制它模仿的遗留系统。
遗留系统已经记录了传入的参数。从新实现开始将包装旧系统,所以我希望记录进入C#版本的参数,以便我可以验证正确的参数以正确的顺序传递。
我只是想记录参数值和顺序,而不是它们的名字。
答案 0 :(得分:7)
如果您使用Postsharp,则只需向要记录的方法添加属性即可。在此属性中,您可以编写日志记录代码,还将提供所需的参数。这被称为横切关注点和AOP(面向方面编程)
答案 1 :(得分:4)
我不确定访问调用堆栈的API是否提供了获取参数列表的方法。
但是有一些方法可以注入IL来拦截方法调用并执行自定义代码。
我经常使用的库是Gael Fraiteur的PostSharp,它包含一个运行postbuild的应用程序,并根据您使用的方面在输出程序集中注入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)
{
//..
}
答案 2 :(得分:2)
好吧,如果您只想传递值,可以欺骗并定义一个对象数组:
public static void LogParameters(params object[] vals)
{
}
这将导致对值类型进行装箱,但也不会为您提供任何参数名称。
说我有方法:
public void SomeMethod(String p1, String p2, int p3)
{
#if DEBUG
LogParamaters(p1, p2, p3);
#endif
// Do Normal stuff in the method
}
更新:很遗憾,反射不会自动为您完成所有操作。您需要提供值,但您可以使用反射来提供参数名称/类型:
How can you get the names of method parameters?
因此方法sig将改为:
public static void LogParameters(string[] methodNames, params object[] vals)
{ }
然后,您可以强制执行/假设每个集合中的每个索引都符合要求,以使methodNames[0]
具有值vals[0]
。
答案 3 :(得分:1)
好params帮助进行日志调用,但不会帮助现有的方法签名。使用AOP framework进行日志记录可能是一种更有效的方法吗?
答案 4 :(得分:1)
当然可以......查看这篇文章,它获得了参数的实际值。 how to enumerate passed method parameters
答案 5 :(得分:0)
动态类型系统有一些功能可以做到,但是你的类需要继承动态基类
答案 6 :(得分:0)
可能在某些情况下不起作用,但应该让你开始:)
class Program
{
static void Main(string[] args)
{
M1("test");
M2("test", "test2");
M3("test", "test2", 1);
Console.ReadKey();
}
static void M1(string p1)
{
Log(MethodBase.GetCurrentMethod());
}
static void M2(string p1, string p2)
{
Log(MethodBase.GetCurrentMethod());
}
static void M3(string p1, string p2, int p3)
{
Log(MethodBase.GetCurrentMethod());
}
static void Log(MethodBase method)
{
Console.WriteLine("Method: {0}", method.Name);
foreach (ParameterInfo param in method.GetParameters())
{
Console.WriteLine("ParameterName: {0}, ParameterType: {1}", param.Name, param.ParameterType.Name);
}
}
}
答案 7 :(得分:0)
只要您知道期望的类型,就可以将它们记录在SQL数据库中。编写一个执行类型检查的方法,然后使用参数(参数)值填充相应的DB列。如果您有自定义类型,则可以使用类型名称并将其作为字符串保存在其自己的特殊列中。
- 编辑
此外,使用MethodBase.Name
扩展方法,您可以将参数与将其作为参数的方法相关联,如下面另一篇文章中所述。是一种方便的方法来跟踪所使用的所有方法,以及哪些参数,以及哪种类型。
这甚至是一个好主意吗? :)
答案 8 :(得分:0)
以下是我提出的解决方案:
PostSharp或其他AOP解决方案在这种情况下并不实用,所以不幸的是我不得不放弃这个想法。
虽然可以使用反射来参数名称和类型,但访问运行时值的唯一方法是附加调试器。
有关详细信息,请参阅此处:
microsoft.public.dotnet.framework
所以这仍然让我遇到了需要手动添加日志的约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 []数组,该数组使用传递给方法的参数和包含参数和方法名称的Log调用进行初始化。
示例输出:
object[] args = {username, password, name, startDate, endDate, cost};
Log("GetAwesomeData",args);
然后可以将此块粘贴到方法的顶部以实现所需的效果。
它比我想要的更加手动,但它比手动输入参数要好得多,而且更不容易出错。