sách gpt4 ai đã đi

c# - 注册、解决、 Release模式使用

In lại 作者:行者123 更新时间:2023-11-30 15:15:07 hai mươi bốn 4
mua khóa gpt4 Nike

我正在读这本书 Dependency Injection in .NET马克西曼。在这本书中,他推荐了注册、解决、发布模式,还建议这些操作中的每一个都应该在您的应用程序代码中只出现一次。

我的情况如下:我正在创建一个应用程序,它使用专有通信协议(protocol)与 PLC(一种工业嵌入式计算机)通信,PLC 制造商为其提供了一个库。该库的文档建议创建到 PLC 的连接并保持打开状态;然后使用计时器或 while 循环,应定期发送请求以读取 PLC 内存中随时间变化的内容。

从 PLC 的内存中读取的值应该用于对数据库进行操作,为此我打算使用 Entity Framework 。据我了解,最好的选择是在每次循环执行时创建一个新的 dbContext 以避免停顿缓存或并发问题(循环可能每隔几毫秒执行一次很长一段时间连接一直保持打开的时间)。

我的第一个选择是在应用程序构建时调用 Resolve 以创建一个长期存在的对象,该对象将与 PLC 通信对象一起注入(inject)并处理循环执行并保持连接有效。然后,在每次循环执行开始时,我打算再次调用 Resolve 以创建一个短期对象,该对象将被注入(inject)一个新的 dbContext 并在数据库上执行操作。然而,在阅读了那本书的建议后,我怀疑我是否走在正确的轨道上。

我的第一个想法是在构造时将委托(delegate)传递给长生命周期对象,这将允许它构建短生命周期对象的新实例(我相信这是工厂模式),从而消除对来 self 长期存在的对象的 DI 容器。然而,这个构造仍然违反了上述模式。

在这种情况下,哪种方式才是处理依赖注入(inject)的正确方法?

我第一次没有 DI 的尝试:

class NaiveAttempt
{
private PlcCommunicationObject plcCommunicationObject;
private Timer repeatedExecutionTimer;

public NaiveAttempt()
{
plcCommunicationObject = new PlcCommunicationObject("192.168.0.10");
plcCommunicationObject.Connect();

repeatedExecutionTimer = new Timer(100); //Read values from PLC every 100ms
repeatedExecutionTimer.Elapsed += (_, __) =>
{
var memoryContents = plcCommunicationObject.ReadMemoryContents();
using (var ctx = new DbContext())
{
// Operate upon database
ctx.SaveChanges();
}
}
}
}

第二次尝试使用穷人的 DI。

class OneLoopObject
{
private PlcCommunicationObject plcCommunicationObject;
private Func dbContextFactory;

public OneLoopObject(PlcCommunicationObject plcCommunicationObject, DbContext dbContext
{
this.plcCommunicationObject = plcCommunicationObject;
this.dbContext = dbContext;
}

public void Execute()
{
var memoryContents = plcCommunicationObject.ReadMemoryContents();
// Operate upon database
}
}

class LongLivedObject
{
private PlcCommunicationObject plcCommunicationObject;
private Timer repeatedExecutionTimer;
private Func oneLoopObjectFactory;

public LongLivedObject(PlcCommunicationObject plcCommunicationObject, Func oneLoopObjectFactory)
{
this.plcCommunicationObject = plcCommunicationObject;
this.dbContextFactory = dbContextFactory;
this repeatedExecutionTimer = new Timer(100);
this.repeatedExecutionTimer.Elapsed += (_, __) =>
{
var loopObject = oneLoopObjectFactory(plcCommunicationObject);
loopObject.Execute();
}
}
}

static class Program
{
static void Main()
{
Func oneLoopObjectFactory = plc => new OneLoopObject(plc, new DbContext());
var myObject = LongLivedObject(new PlcCommunicationObject("192.168.1.1"), oneLoopObjectFactory)

Console.ReadLine();
}
}

1 Câu trả lời

第一版指出(第 3 章,第 82 页):

In its pure form, the Register Resolve Release pattern states that you should only make a single method call in each phase [...] an application should only contain a single call to the Resolve phương pháp.

此描述源于您的应用程序仅包含一个根对象(通常在编写简单的控制台应用程序时)或一组逻辑根类型的想法,例如MVC Controller 。例如,对于 MVC Controller ,您将拥有一个自定义 Controller 工厂,它由 MVC 框架提供,并带有要构建的 Controller 类型。在这种情况下,该工厂在提供类型时只会调用一次 Resolve.

但是,在某些情况下,您的应用程序有多个根类型组。例如,Web 应用程序可以混合使用 API Controller 、MVC Controller 和 View 组件。对于每个逻辑组,您可能会在应用程序中对 Resolve 进行一次调用,因此对 Resolve 进行多次调用(通常是因为每个根类型都有自己的工厂)。

回调容器还有其他正当理由。例如,您可能希望推迟构建对象图的一部分,以解决 Captive Dependencies 的问题。 .这似乎是你的情况。进行额外解析的另一个原因是当您使用调解器模式将消息分派(dispatch)给可以处理该消息的特定实现(或多个实现)时。在那种情况下,您的调解器实现通常会包装容器并调用 Resolve。 Mediator 的抽象可能会在您的域库中定义,而 Mediator 的实现及其对容器的了解应该在 inside Composition Root 中定义。 .

因此,不应按字面意思理解对 Resolve 进行一次调用的建议。这里的实际目标是在一次调用中尽可能多地构建一个对象图,而不是让类自己回调到容器中来解决它们的依赖关系(即 Service Locator anti-pattern ).

本书提出的另一个重要观点(second edition)是

Querying for Dependencies, even if through a DI Container, becomes a Service Locator if used incorrectly. When application code (as opposed to infrastructure code) actively queries a service in order to be provided with required Dependencies, then it has become a Service Locator.

A DI Container encapsulated in a Composition Root isn't a Service Locator—it's an infrastructure component.

(注意:此引用来自 second edition ;虽然第一版也包含此信息,但表述可能有所不同)。

因此 RRR 模式的目标是促进组合根中 DI 容器的封装,这就是它坚持对 Resolve 进行一次调用的原因。

请注意,在编写 second edition 时, Mark 和我想重写对 RRR 模式的讨论。这样做的主要原因是我们发现文本令人困惑(如您的问题所示)。然而,我们最终没时间了,所以我们决定简单地删除那个详尽的讨论。我们认为最重要的几点已经提出。

关于c# - 注册、解决、 Release模式使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53268326/

hai mươi bốn 4 0
Bài viết được đề xuất: c# - 为什么 Directory.GetDirectories 输出与 dir with/a :d? 不同
Bài viết được đề xuất: c - 用户定义的端口号
Bài viết được đề xuất: c - 读取数据并重新格式化,以换行符分隔
Bài viết được đề xuất: c# - 您有使前景像背景一样工作的解决方案吗?
行者123
Hồ sơ cá nhân

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá Didi Taxi miễn phí
Mã giảm giá Didi Taxi
Giấy chứng nhận ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com