C# 依赖注入:我不&x27;我不知道从哪里开始!

C# 依赖注入:我不&x27;我不知道从哪里开始!,c#,winforms,design-patterns,dependency-injection,C#,Winforms,Design Patterns,Dependency Injection,我有几篇关于依赖注入的文章,我可以看到它的好处,特别是在单元测试方面。这些单元可以松散耦合,并且可以模拟依赖关系 问题是——我就是不知道从哪里开始 考虑下面这段代码片段(为了本文的目的进行了大量编辑)。我正在从主窗体实例化一个Plc对象,并通过Connect方法以通信模式进行传递 以目前的形式,它变得很难测试,因为我无法将Plc与CommsChannel隔离开来进行单元测试。(我可以吗?) 该类依赖于使用CommsChannel对象,但我只传递用于在Plc本身中创建此通道的模式。要使用依赖注入,

我有几篇关于依赖注入的文章,我可以看到它的好处,特别是在单元测试方面。这些单元可以松散耦合,并且可以模拟依赖关系

问题是——我就是不知道从哪里开始

考虑下面这段代码片段(为了本文的目的进行了大量编辑)。我正在从主窗体实例化一个Plc对象,并通过Connect方法以通信模式进行传递

以目前的形式,它变得很难测试,因为我无法将Plc与CommsChannel隔离开来进行单元测试。(我可以吗?)

该类依赖于使用CommsChannel对象,但我只传递用于在Plc本身中创建此通道的模式。要使用依赖注入,我应该将已经创建的CommsChannel(可能通过“ICommsChannel”接口)传递给Connect方法,或者通过Plc构造函数。是这样吗

但这意味着首先在我的主窗体中创建CommsChannel,这似乎也不正确,因为感觉一切都会回到主窗体的底层,一切都从那里开始。不知何故,我觉得我错过了拼图的一个关键部分

你从哪里开始?你必须在某处创建一个实例,但我很难理解它应该在哪里

public class Plc()
{
    public bool Connect(CommsMode commsMode)
    {
        bool success = false;

        // Create new comms channel.
        this._commsChannel = this.GetCommsChannel(commsMode);

        // Attempt connection
        success = this._commsChannel.Connect();  

        return this._connected;
    }

    private CommsChannel GetCommsChannel(CommsMode mode)
    {
        CommsChannel channel;

        switch (mode)
        {
            case CommsMode.RS232:
                channel = new SerialCommsChannel(
                    SerialCommsSettings.Default.ComPort,
                    SerialCommsSettings.Default.BaudRate,
                    SerialCommsSettings.Default.DataBits,
                    SerialCommsSettings.Default.Parity,
                    SerialCommsSettings.Default.StopBits);
                break;

            case CommsMode.Tcp:
                channel = new TcpCommsChannel(
                    TCPCommsSettings.Default.IP_Address,
                    TCPCommsSettings.Default.Port);
                break;

            default:
                // Throw unknown comms channel exception.
        }

        return channel;
    }
}

很难回答这样一个广泛的问题,但是您关于在哪里/谁创建连接对象的具体问题更简单

您可以传入一个factory对象,该对象知道如何创建连接对象以及或代替模式。这样,如果您想创建不同的(例如,mock)连接,您只需传入一个不同的工厂对象,当要求创建一个连接时,该工厂对象会创建一个不同的连接实现

这有帮助吗,还是我错过了真正的问题?

我会怎么做

依赖注入是应用S.O.L.I.D原则时迟早会遇到的问题,因此,与其直接投入行动,不如花点时间阅读这篇优秀的pdf

然后结帐

例如


这是我一生中最棒的一次旅行,希望这对你来说也是一次同样激动人心的经历。

相关:你是否阅读了“编写应用程序的位置”上的依赖项注入标签简介/常见问题解答:@Mark:我没有看到那个常见问题解答,谢谢。谢谢,这确实有帮助。好的,那么一个CommsChannelFactory。。。你的意思是说有一个使用ICommsChannelFactory接口的工厂,然后在单元测试时用这个接口创建一个MockCommsChannelFactory,然后返回一个伪ICommsChannel对象?(我说的对吗?!)我觉得这是对的。归根结底,一个对象/实现的可插拔性如何,但要保持一定的平衡,否则最终会导致接口和注入的指数级增长,我发现这会导致难以理解的系统。“难以理解”我不需要:)这个例子似乎是一个自然的界面分离关注点的地方,使测试更容易,但我接受你的观点。我们正在讨论的工厂示例是一个完美的界面。令人担忧的是,如果人们做得太多而没有真正的价值,那么你最终会得到大量的小类,这会使系统难以理解,除非你完全理解设计者的心智模型。因此,我的建议是,当你意识到你应该有更多的注入,而不是不断地将其分散到任何地方时,使用好的工具并无情地进行重构。我决定进行重构,将ICommsChannel实例传递给独立工厂生产的Plc。这将至少允许我使用一些模拟通道对Plc进行单元测试。我会接受你的回答,因为这让我想到了这些,谢谢。