我想在几种方法之前和之后调用一些记录逻辑。每种方法都接受不同数量/类型的参数。我正在尝试设置它,所以当我调用每个方法时,我不必复制日志记录逻辑。我已经能够通过创建一些代表来减少重复的数量。我为每个使用的parms数量/类型创建了一个委托,我有一个接受每个委托并进行日志记录的方法。但是,我仍然有大约6个不同的代表,因此这六个逻辑重复。
我认为无论parms的数量如何,都可以修改它,我有一种方法可以进行日志记录并调用方法。但我无法弄明白。
以下是其中一个代表和我试图不重复的逻辑示例。
public delegate void LineOfBusinessHandler(DateTime runDate, LineOfBusinessCode lineOfBusinessCode);
public void Run(DateTime runDate, ProcessCode process, LineOfBusinessCode lineOfBusinessCode, LineOfBusinessHandler del)
{
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Started.ToString(), null, runDate);
try
{
del(runDate, lineOfBusinessCode);
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Finished.ToString(), null, runDate);
}
catch (Exception e)
{
int errorId = SystemManager.LogError(e, process.ToString());
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Errored.ToString(), errorId, runDate);
}
}
答案 0 :(得分:1)
我意识到这可能超出了你所寻找的范围和/或能力。但是如果你有一个通用的日志记录逻辑,你希望在不同的方法调用上重用,而不会丢失类型安全(即不在object[]
中传递你的参数),那么走的方法是拦截。你需要一个框架(我不建议你自己编写自己的框架!),它可以提供AOP,依赖注入或类似的东西。这些事情通常可以处理拦截。
例如,我有一个与Ninject一起使用的日志拦截器:
public void Intercept(IInvocation invocation)
{
var logger = LoggerFactory.GetLogger(invocation.Request.Method.DeclaringType);
var debug = !invocation.Request.Method.IsSpecialName && logger.IsDebugEnabled;
if (debug)
logger.Debug(invocation.Request.Method.Name);
try
{
invocation.Proceed();
if (debug)
logger.Debug(invocation.Request.Method.Name + " FINISH");
}
catch (Exception)
{
logger.Error(invocation.Request.Method.Name + " ERROR");
throw;
}
}
然后我通过使用Ninject获取它们来创建我的对象(如果您不知道它,请查看一些tutorials),同时向它们添加一些拦截,例如:Kernel.Bind<MyTypeToLog>().ToSelf().Intercept().With<LoggingInterceptor>();
其中{ {1}}使用上面显示的方法实现LoggingInterceptor
...
如果您需要更多细节帮助,请说出来!
编辑:刚才意识到我的示例没有显示这个,但你也可以访问调用的参数(作为对象集合)!!
答案 1 :(得分:0)
如果我正确理解您的问题,听起来您可以使用C# params 关键字。有关如何使用它的参考,请参阅此内容:http://msdn.microsoft.com/en-us/library/w5zay9db.aspx
使用 params 时的一个要求是它必须放在函数签名的最后。然后,在函数内部,您可以枚举并遍历变量参数列表,就像它是一个数组一样。
修改强>
要扩展@Ben Voigt发布的评论,使用 params 关键字的另一个限制是它要求变量参数列表属于同一类型。然而,这可以在您的情况下减轻,因为您关心的只是记录。在这种情况下,您可能会在需要记录的对象上调用ToString()方法,因此您可以创建类型为object的变量参数列表。
如果调用ToString()是不够的,并且您有不同类型的对象,则可以使所有这些对象实现公共接口。我们称之为ILoggableObject
,它公开了一种提供日志输出的方法。如果你有能力改变这些对象的话。
答案 2 :(得分:0)
C#语言没有任何元编程语法。你必须使用反射。您当然可以反映任意方法/委托来确定参数类型,然后构建一个记录参数并调用原始方法的方法,编译这个新的包装器方法,并返回一个与原始方法具有相同调用签名的委托。
您可以在运行时执行此操作(返回委托)或使用所有包装函数构建新程序集,然后由代码引用并正常使用。
您应该查看用于面向方面编程的代码编织工具。其中一些人已经这样做了。
与使用params数组不同,这为您提供了一个与原始方法具有相同签名(或委托类型)的包装器,因此它是类型安全的并且Intellisense可以工作(与任何其他委托一样多。)
答案 3 :(得分:0)
这取决于不同版本之间的共同点,但假设runDate和process很常见,你可以这样做:
public void Run(DateTime runDate, ProcessCode process, LineOfBusinessCode lineOfBusinessCode, LineOfBusinessHandler del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, lineOfBusinessCode));
}
public void DoRun(DateTime runDate, ProcessCode process, Action<DateTime, ProcessCode> action)
{
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Started.ToString(), null, runDate);
try
{
action(runDate, process);
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Finished.ToString(), null, runDate);
}
catch (Exception e)
{
int errorId = SystemManager.LogError(e, process.ToString());
this.ProcessManager.AddToBatchLog(process.ToString(), ProcessStatus.Errored.ToString(), errorId, runDate);
}
}
您甚至可以进行概括,因此您无需像这样定义自定义委托:
public void Run<T1>(DateTime runDate, ProcessCode process, T1 param1, Action<DateTime, ProcessCode, T1> del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, param1));
}
public void Run<T1, T2>(DateTime runDate, ProcessCode process, T1 param1, T2 param2, Action<DateTime, ProcessCode, T1, T2> del)
{
this.DoRun(runDate, process, (d, p) => del(d, p, param1, param2));
}