0

我有一些日志记录逻辑,我想在几种方法之前和之后调用。每种方法都接受不同数量/类型的参数。我正在尝试对其进行设置,以便在调用每个方法时不必复制日志记录逻辑。通过创建一些代表,我已经能够减少重复的数量。我为使用的每个数量/类型的参数创建了一个委托,并且我有一个接受每个委托并进行日志记录的方法。但是,我仍然有大约 6 个不同的代表,因此这六个的逻辑是重复的。

我认为可以修改它,因此无论参数的数量如何,我都有一种方法可以进行日志记录并调用该方法。但我一直无法弄清楚。

下面是其中一位代表的示例以及我试图不重复的逻辑。

    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);
        }
    }
4

4 回答 4

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 获取它们来创建我的对象(如果您不了解它,请查看一些教程),同时向它们添加一些拦截,例如:使用上面显示的方法实现的Kernel.Bind<MyTypeToLog>().ToSelf().Intercept().With<LoggingInterceptor>();地方......LoggingInterceptorIInterceptor

只是说如果你需要更多的细节帮助!

编辑:刚刚意识到我的示例没有显示这一点,但是您也可以访问调用的参数(尽管作为对象集合)!

于 2012-11-05T15:27:15.137 回答
0

如果我正确理解您的问题,听起来您可以使用 C# params关键字。有关如何使用它的参考,请参阅此:http: //msdn.microsoft.com/en-us/library/w5zay9db.aspx

使用参数时的要求之一是它必须放在函数签名的最后。然后,在函数内部,您可以枚举和迭代变量参数列表,就好像它是一个数组一样。

编辑

为了扩展@Ben Voigt 发表的评论,使用params关键字的另一个限制是它要求可变参数列表具有相同的类型。但是,这可以在您的情况下得到缓解,因为您关心的只是日志记录。在这种情况下,您可能会在需要记录的对象上调用 ToString() 方法,这样您就可以将变量参数列表设为对象类型。

如果调用 ToString() 还不够,并且您有不同类型的对象,您可以使所有这些对象实现一个通用接口。我们称它为ILoggableObject公开提供日志输出的方法。那就是如果您有能力更改这些对象。

于 2012-11-05T15:14:43.820 回答
0

C# 语言没有任何元编程语法。你必须使用反射。您当然可以针对任意方法/委托进行反射以确定参数类型,然后构建一个记录参数并调用原始方法的方法,编译这个新的包装器方法,并返回一个与原始方法具有相同调用签名的委托。

您可以在运行时执行此操作(返回委托)或使用所有包装函数构建新程序集,然后您的代码可以引用并正常使用该程序集。

您应该查看用于面向方面编程的代码编织工具。他们中的一些人已经这样做了。

与使用 params 数组不同,这为您提供了一个与原始方法具有相同签名(或委托类型)的包装器,因此它是类型安全的并且 Intellisense 可以工作(与任何其他委托一样)。

于 2012-11-05T15:21:34.530 回答
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));
}
于 2012-11-05T15:24:46.397 回答