C# 不考虑PARM数量的重用逻辑的模式
我想在几个方法之前和之后调用一些日志逻辑。每个方法接受不同数量/类型的参数。我正在尝试设置它,以便在调用每个方法时不必重复日志逻辑。我已经能够通过创建一些代理来减少重复的数量。我已经为使用的每种数量/类型的PARM创建了一个委托,并且我有一个接受每个委托并进行日志记录的方法。然而,我仍然有大约6个不同的代表,因此这6个代表的逻辑是重复的 我认为需要修改它,所以不管parm的数量如何,我有一个方法来记录日志并调用该方法。但我还没弄明白 下面是一个代表的例子和我不想重复的逻辑C# 不考虑PARM数量的重用逻辑的模式,c#,logging,C#,Logging,我想在几个方法之前和之后调用一些日志逻辑。每个方法接受不同数量/类型的参数。我正在尝试设置它,以便在调用每个方法时不必重复日志逻辑。我已经能够通过创建一些代理来减少重复的数量。我已经为使用的每种数量/类型的PARM创建了一个委托,并且我有一个接受每个委托并进行日志记录的方法。然而,我仍然有大约6个不同的代表,因此这6个代表的逻辑是重复的 我认为需要修改它,所以不管parm的数量如何,我有一个方法来记录日志并调用该方法。但我还没弄明白 下面是一个代表的例子和我不想重复的逻辑 public
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);
}
}
如果我正确理解了你的问题,听起来你可以使用C#params关键字。有关如何使用它的参考信息,请参见: 使用参数时的一个要求是必须将其放在函数签名的最后。然后,在函数内部,您可以枚举和迭代变量参数列表,就像它是一个数组一样 编辑 要扩展@Ben Voigt发布的评论,使用params关键字的另一个限制是它要求变量参数列表的类型相同。但是,在您的情况下,这可以减轻,因为您只关心日志记录。在本例中,您可能会对需要记录的对象调用ToString()方法,以便创建object类型的变量参数列表 如果调用ToString()是不够的,并且您有不同类型的对象,您可以使所有这些对象实现一个公共接口。让我们称之为
ilogableobject
,它公开了一个提供日志输出的方法。如果您能够更改这些对象,则可以这样做。C语言没有任何元编程语法。你必须使用反射。您当然可以对任意方法/委托进行反思,以确定参数类型,然后构建一个记录参数并调用原始方法的方法,编译这个新的包装器方法,并返回一个与原始方法具有相同调用签名的委托
您可以在运行时执行此操作(返回一个委托),或者使用所有包装函数构建一个新的程序集,然后代码可以引用该程序集并正常使用
您应该了解用于面向方面编程的代码编织工具。他们中的一些人已经这样做了
与使用params数组不同,这将为您提供一个与原始方法具有相同签名(或委托类型)的包装器,因此它是类型安全的,Intellisense可以工作(与任何其他委托一样)。这取决于不同版本之间的共同点,但假设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(日期时间运行日期、流程代码流程、业务代码行、业务处理程序行)
{
DoRun(运行日期,进程,(d,p)=>del(d,p,业务代码行));
}
public void DoRun(日期时间运行日期、流程代码流程、操作)
{
this.ProcessManager.AddToBatchLog(process.ToString(),ProcessStatus.Started.ToString(),null,runDate);
尝试
{
操作(运行日期、进程);
this.ProcessManager.AddToBatchLog(process.ToString(),ProcessStatus.Finished.ToString(),null,runDate);
}
捕获(例外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));
}
public void运行(DateTime runDate,ProcessCode进程,T1参数1,Action del)
{
DoRun(runDate,process,(d,p)=>del(d,p,param1));
}
public void运行(DateTime runDate、ProcessCode进程、T1参数1、T2参数2、Action del)
{
DoRun(runDate,process,(d,p)=>del(d,p,param1,param2));
}
我意识到这可能超出了您所寻找的范围和/或能力。但是,如果您有一个通用的日志逻辑,希望在不同的方法调用上重用,而不丢失类型安全性(即不在对象[]
中传递参数),那么方法就是拦截。您需要一个能够提供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获取对象(如果您不知道,请查看一些),同时向对象添加一些拦截来创建对象,例如:Kernel.Bind().ToSelf().Intercept().with()代码>其中LoggingInterceptor
使用上述方法实现IInterceptor
只要说你需要更多的细节帮助
编辑:刚刚意识到我的示例没有显示这一点,但是您也可以访问调用的参数(作为对象集合) 当参数都是不同的类型时,这有什么帮助?@Ben Voigt-您创建类型object的变量参数列表。非常类似于Console.Write()函数的签名。因为这是用于日志记录的,所以您可能只需要在它们上调用ToString。但是它们仍然需要传递给真正的函数。@Ben Voigt-也许我不理解他的问题。。我认为他控制(设计)了日志框架。请看那一行del(runDate,lineOfBusinessCode)
。这需要在记录调用之间完成,转发传入的参数。如果丢失了参数的类型