如何重构传递过多的上下文?

时间:2018-03-29 12:02:01

标签: c#

我有一个类,用于存储有关当前操作上下文的信息。例如,每个动作都属于某个动作块,因此对于日志记录(以及许多其他目的),我会传递该类的实例,该类存储哪个动作块:

ExecuteAction(action,context);

这让我记录如下内容:

var logString = $"action{action.Name} was executed as part of {context.ActionBlockName} action block";

能够获取当前动作块非常重要,因为在不同的动作块中执行相同的动作,并且在任何给定时间都可以有任意数量的活动上下文。

然而,我的代码相当复杂,成千上万的方法调用相互分层,我经常需要在5-6个不同的方法调用内部形成日志字符串,这意味着这个context只是传递得过多并且在大多数方法签名中。

我正在考虑将所有上下文信息写入文件或数据库以供所有访问方法使用,但是他们仍然需要在所有活动方法中查找当前上下文。这意味着我将不得不传递某种上下文密钥,这并不比传递上下文本身好。

有更好的方法吗?

理想情况下,我需要的结果是能够调用ExecuteAction(action);而不在action中存储任何上下文信息,同时能够以某种方式找出ExecuteAction内的上下文

1 个答案:

答案 0 :(得分:1)

有几种方法可以想到:

1)依赖注入:在过去几年中,使用依赖注入容器来帮助解决这个问题很受欢迎。我们的想法是创建您的上下文对象,然后使用DI容器注册一个对象以获取对它的访问权限,可能类似于CurrentContextAccessor,它上面有一个GetCurrent方法。该方法将容纳逻辑以知道哪个上下文对象是"当前对象"。然后,所有需要访问此上下文的对象都将在DI容器中注册,并将CurrentContextAccessor对象指定为构造函数参数,这样当您从DI容器中获取此类对象时,它会自动将CurrentContextAccessor对象注入其中。构造函数,以便它可以访问当前上下文。

ASP.NET Core是基于此方法构建的系统的示例。这种方法的一个优点是只有你的对象的构造方法需要传入CurrentContextAccessor,而不是它的方法需要它,因为它们可以通过成员变量在内部访问上下文。构造函数存储了当前上下文。并且您不必专门将CurrentContextAccessor传递给您向DI容器注册的任何对象,因为当从DI容器请求对象时,它将自动注入到该对象中。这种方法的另一个原因是它导致松散耦合的代码,应该可以轻松地进行单元测试。这种方法的一个缺点是DI容器以及以这种方式使用它们可以为需要维护代码的开发人员创建学习曲线,并且有人会认为它使得程序中的控制流更难以遵循。

2)全局静态访问器您可以创建一个创建静态方法,该方法挂起一些全局可访问的类,该类提供对当前上下文的访问。这样做的优点是比第一种方法更容易实现,并且初级开发人员更容易遵循代码中的控制流程。但它将所有类紧密地耦合到全局静态变量,这使得在其他项目中重用类更加困难,并且很难在使用全局静态上下文访问器的代码上运行单元测试。 ASP.NET Full框架提供了HttpContext.Current,这是此方法的一个示例。

还有其他方法,例如服务定位器模式(你可以谷歌),但它通常仍然使用DI容器(虽然它不必),仍然使对象难以进行单元测试。因此,除非您想出一个真正的切割器实现,否则您将从上面列出的两种方法中获得缺点。