C#: 记录传递给方法的所有参数






4.77/5 (11投票s)
在 C# 中记录传递给某个方法的所有参数
引言
异常在任何项目中都很常见。为了跟踪异常,我们使用错误记录器,这些记录器可能只会记录异常细节和一些额外的信息。但我们很难知道对于哪一组输入(参数和值)方法抛出了错误。
参数记录实用工具
这里是实用工具类,我们可以使用它来跟踪异常期间的 参数
值。
internal class ParamLogUtility
{
private readonly String _methodName;
private String _paramaterLog;
private readonly JavaScriptSerializer _serializer;
private readonly Dictionary<String, Type> _methodParamaters;
private readonly List<Tuple<String, Type, object>>_providedParametars;
public ParamLogUtility(params Expression<Func<object>>[] providedParameters)
{
try
{
_serializer = new JavaScriptSerializer();
var currentMethod = new StackTrace().GetFrame(1).GetMethod();
/*Set class and current method info*/
_methodName = String.Format("Class = {0}, Method = {1}",
currentMethod.DeclaringType.FullName, currentMethod.Name);
/*Get current methods parameters*/
_methodParamaters = new Dictionary<string, Type>();
(from aParamater in currentMethod.GetParameters()
select new { Name = aParamater.Name, DataType = aParamater.ParameterType })
.ToList()
.ForEach(obj => _methodParamaters.Add(obj.Name, obj.DataType));
/*Get provided methods parameters*/
_providedParametars = new List<Tuple<string, Type, object>>();
foreach (var aExpression in providedParameters)
{
Expression bodyType = aExpression.Body;
if (bodyType is MemberExpression)
{
AddProvidedParamaterDetail((MemberExpression)aExpression.Body);
}
else if (bodyType is UnaryExpression)
{
UnaryExpression unaryExpression = (UnaryExpression)aExpression.Body;
AddProvidedParamaterDetail((MemberExpression)unaryExpression.Operand);
}
else
{
throw new Exception("Expression type unknown.");
}
}
/*Process log for all method parameters*/
ProcessLog();
}
catch (Exception exception)
{
throw new Exception("Error in paramater log processing.", exception);
}
}
private void ProcessLog()
{
try
{
foreach (var aMethodParamater in _methodParamaters)
{
var aParameter =
_providedParametars.Where(
obj => obj.Item1.Equals(aMethodParamater.Key) &&
obj.Item2 == aMethodParamater.Value).Single();
_paramaterLog += String.Format(@" ""{0}"":{1},",
aParameter.Item1, _serializer.Serialize(aParameter.Item3));
}
_paramaterLog = (_paramaterLog != null) ?
_paramaterLog.Trim(' ', ',') : string.Empty;
}
catch (Exception exception)
{
throw new Exception("MathodParamater is not found in providedParameters.");
}
}
private void AddProvidedParamaterDetail(MemberExpression memberExpression)
{
ConstantExpression constantExpression =
(ConstantExpression) memberExpression.Expression;
var name = memberExpression.Member.Name;
var value = ((FieldInfo)
memberExpression.Member).GetValue(constantExpression.Value);
var type = value.GetType();
_providedParametars.Add(new Tuple<string, Type, object>(name, type, value));
}
public String GetLog()
{
return String.Format("{0}({1})", _methodName, _paramaterLog);
}
}
- 在构造函数内部,
ParamLogUtility(params Expression<Func<object>>[] providedParameters)
我们将传递所有期望的方法参数。 GetLog()
将返回错误日志字符串
使用日志实用工具
要使用这段代码,我们可能需要在我们的项目中添加 System.Web.Extensions.dll 引用,该引用位于以下位置附近
C:\Program Files
(x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Web.Extensions.dll
如果方法包含任何参数,我们将像这样使用该实用工具类
private void Add(string id, int age, string name, PersonEntity aPersonEntity)
{
try
{
throw new NotImplementedException();
}
catch (Exception exception)
{
/*gives the log*/
var paramLog = new ParamLogUtility(() => aPersonEntity,
() => age, () => id, () => name).GetLog();
}
}
并非所有方法都应该有参数。如果没有参数,我们可以像这样使用它
var paramLog = new ParamLogUtility().GetLog();
日志字符串示例
Class = MethodParamatersLog.Program, Method = Add("id":"1",
"age":24, "name":"Dipon",
"aPersonEntity":{"CreatedDateTime":"\/Date(1405115574273)\/",
"Id":"1","Name":"Dipon","Age":24})
限制
这个记录器有一些限制,例如
- 只有在方法签名中指定的参数才能参与日志过程。如果在过程中添加一些额外的变量,它会抛出一个错误,例如这里
aPersonEntity
不是方法签名的一部分。private static void Add(string id, int age, string name) { PersonEntity aPersonEntity = new PersonEntity(); try { throw new NotImplementedException(); } catch (Exception exception) { /*aPersonEntity would not take part in log process, as it is not used in methods signature, and with throw error */ var paramLog = new ParamLogUtility(() => aPersonEntity, () => age, () => id, () => name).GetLog(); var error = exception; } }
- 方法的全部参数都应该参与日志过程。否则,它会抛出一个错误。这一点很重要,因为我们有时可能会忘记将方法参数添加到日志字符串中。这个错误会提醒我们使用这些未使用的参数。
private static void Add(string id, int age, string name) { PersonEntity aPersonEntity = new PersonEntity(); try { throw new NotImplementedException(); } catch (Exception exception) { /*did n't pointed all the parameters of the method(id, age)*/ var paramLog = new ParamLogUtility(() => name).GetLog(); var error = exception; } }
- 也可能存在其他我尚未遇到的错误。所以如果您发现任何错误,请告诉我。
- 我们应该将这个实用工具应用到每个方法吗?显然不是!
您可以在附件中找到 VS 2013 解决方案的示例项目。
历史
- 2014 年 7 月 13 日:初始版本