使用控制反转范例创建自定义对象列表

Create a list of custom objects with Inversion of Control paradigm

我想将依赖注入和控制反转应用到我的日常开发中。假设我有一个 SomeObject 的对象类型(实现接口 ISomeObject)。我有一个 class,它使用这个名为 Data 的对象,它实现了 IData 接口。

public interface ISomeObject {
    int ID;
    string Name;
    bool IsAwesome;

    void DoSomeStuffIfAwesome();
}

public Class SomeObject : ISomeObject {
    int ID;
    string Name;
    bool IsAwesome;

    void DoSomeStuffIfAwesome() { /*stuff happens here*/ }        
}

public interface IData {
    List<ISomeObject> GetSomeObjects();
}

public Class Data : IData {
    List<ISomeObject> GetSomeObjects()
    {
        List<ISomeObject> objects = new List<ISomeObject>; // ??? Maybe and cast later?

        //do some SQL stuff and get a SqlDataReader object called reader
        while(reader.Read()) {
             //ISomeObject someObj = ???
             //Read into the someObj.ID, someObj.Name and someObj.IsAwesome fields
             objects.add(someObj);
        }
        return objects;
    }
}    

GetSomeObjects() 方法生成 ISomeObject 个对象的列表。但我不希望 Data.cs 将与 SomeObject 相关的任何内容硬编码到其中。我想要某种形式的依赖注入来解决运行时的问题。处理这个问题的最佳方法是什么?我考虑了以下几点:

1.将 SomeObject 的实例传递给 Data 的构造函数。 这样我就可以使用 .GetType() 获取其类型,将其存储到 System.Type 中的私有变量 Data.cs,并在循环中使用 Activator.CreateInstance 来创建要添加到列表中的新对象。如果我理解正确的话,Data 需要知道 SomeObject class 才能具体施放。

2。将我的 IoC 容器实例传递给 Data 的构造函数 ,然后使用 container.Resolve<ISomeObject>() 解析对象类型。如果不使用我的 IoC 容器,这将使 GetSomeObjects() 方法的单元测试变得困难。我读过我不应该在单元测试期间使用 IoC 容器,应该手动将我需要的内容传递到方法中。

3。传递已实例化为 SomeObjectISomeObject 对象 - 然后我将使用它通过一些内置方法创建对象,例如 SomeObject.GenerateList(IDataReader reader).

您可以将对象的创建委托给其他人;

public interface ISomeObjectFactory {
    ISomeObject Create(IDataReader reader);
}

它只负责创建 ISomeObject

的实例
using System.Collections.Generic;
using System.Data;

public interface IDbConnectionFactory {
    ///<summary>
    ///  Creates a connection based on the given database name or connection string.
    ///</summary>
    IDbConnection CreateConnection(string nameOrConnectionString);
}

public class Data : IData {
    private IDbConnectionFactory dbConnectionFactory;
    ISomeObjectFactory someObjectFactory;
    private string CONNECTION_STRING = "Connection string here";

    public Data(IDbConnectionFactory dbConnectionFactory, ISomeObjectFactory objectFactory) {
        this.dbConnectionFactory = dbConnectionFactory;
        this.someObjectFactory = objectFactory;
    }

    public List<ISomeObject> GetSomeObjects() {
        var objects = new List<ISomeObject>();
        //do some SQL stuff and return a data reader
        using (var connnection = dbConnectionFactory.CreateConnection(CONNECTION_STRING)) {
            using (var command = connnection.CreateCommand()) {
                //configure command to be executed.
                command.CommandText = "SELECT * FROM SOMEOBJECT_TABLE";
                connnection.Open();
                using (var reader = command.ExecuteReader()) {
                    while (reader.Read()) {
                        //...Logic to populate item
                        var someObject = someObjectFactory.Create(reader);
                        if (someObject != null)
                            objects.Add(someObject);
                    }
                }
            }
        }

        return objects;
    }
}

那样 Data 只依赖于抽象而不依赖于具体化。这些可以是运行时组合根中的 determined/configured。