使用Inversion of Control范例创建自定义对象列表

时间:2016-09-07 21:38:34

标签: c# unit-testing dependency-injection inversion-of-control abstraction

我希望将依赖注入和控制反转适应我的日常开发。假设我的对象类型为SomeObject(实现接口ISomeObject)。我有一个类,它使用这个名为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类。

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

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

1 个答案:

答案 0 :(得分:2)

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

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仅依赖于抽象而不依赖于具体结果。这些可以在运行时在组合根中确定/配置。