C# 使用控制反转范例创建自定义对象列表
我想将依赖注入和控制反转适应到我的日常开发中。假设我有一个对象类型C# 使用控制反转范例创建自定义对象列表,c#,unit-testing,dependency-injection,inversion-of-control,abstraction,C#,Unit Testing,Dependency Injection,Inversion Of Control,Abstraction,我想将依赖注入和控制反转适应到我的日常开发中。假设我有一个对象类型SomeObject(实现接口isomoobject)。我有一个类,它使用这个名为Data的对象,它实现了IData接口 public interface ISomeObject { int ID; string Name; bool IsAwesome; void DoSomeStuffIfAwesome(); } public Class SomeObject : ISomeObject {
SomeObject
(实现接口isomoobject
)。我有一个类,它使用这个名为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;
}
}
公共接口对象{
int-ID;
字符串名;
布尔·伊萨维索姆;
void DoSomeStuffIfAwesome();
}
公共类SomeObject:ISomeObject{
int-ID;
字符串名;
布尔·伊萨维索姆;
void DoSomeStuffIfAwesome(){/*这里发生的事情*/}
}
公共接口IData{
列出GetSomeObjects();
}
公共类数据:IData{
列出GetSomeObjects()
{
列表对象=新列表;/??可能以后再强制转换?
//执行一些SQL操作并获得一个名为reader的SqlDataReader对象
while(reader.Read()){
//ISomeObject someObj=???
//读入someObj.ID、someObj.Name和someObj.IsAwesome字段
添加(someObj);
}
归还物品;
}
}
GetSomeObjects()
方法生成isomoObject
对象的列表。但是我不希望Data.cs
将任何与SomeObject
相关的内容硬编码到它中。我需要某种形式的依赖注入来解决运行时的问题。最好的处理方法是什么?我考虑了以下几点:
1。将SomeObject
的实例传递到Data
的构造函数中。这样,我可以使用.GetType()
获取其类型,将其存储到私有系统中。在Data.cs
中键入变量,并在循环中使用Activator.CreateInstance
创建要添加到列表中的新对象<如果我理解正确,代码>数据
需要知道专门用于强制转换的SomeObject
类
2。将我的IoC容器的一个实例传递给数据的构造函数,只需使用container.resolve()
解析对象类型即可。如果不使用IoC容器,这将使单元测试GetSomeObjects()
方法变得困难。我已经读到我不应该在单元测试期间使用IoC容器,应该手动将我需要的传递到方法中
3。传递一个已被实例化为SomeObject
的isomoobject
对象-然后我将使用该对象通过一些内置方法创建对象,例如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;
}
}
使用System.Collections.Generic;
使用系统数据;
公共接口IDbConnectionFactory{
///
///基于给定的数据库名称或连接字符串创建连接。
///
IDbConnection CreateConnection(字符串名称或连接字符串);
}
公共类数据:IData{
私有IDbConnectionFactory dbConnectionFactory;
ISomeObjectFactory someObjectFactory;
私有字符串连接\u string=“此处的连接字符串”;
公共数据(IDbConnectionFactory dbConnectionFactory、ISomeObjectFactory objectFactory){
this.dbConnectionFactory=dbConnectionFactory;
this.someObjectFactory=objectFactory;
}
公共列表GetSomeObjects(){
var objects=新列表();
//执行一些SQL操作并返回一个数据读取器
使用(var connnection=dbConnectionFactory.CreateConnection(连接\字符串)){
使用(var command=connnection.CreateCommand()){
//配置要执行的命令。
command.CommandText=“从SOMEOBJECT_表中选择*”;
connection.Open();
使用(var reader=command.ExecuteReader()){
while(reader.Read()){
//…填充项的逻辑
var someObject=someObjectFactory.Create(reader);
if(someObject!=null)
对象。添加(someObject);
}
}
}
}
归还物品;
}
}
这样,数据只依赖于抽象,而不依赖于具体。这些可以在运行时在合成根目录中确定/配置。在某些情况下,类必须是具体的。为什么IData
的实现不知道如何返回一组特定的isomoObject
对象呢?很可能就是这种情况。我的理解是,IoC和依赖注入的目标是让使用者只知道接口,而不知道具体类,这样我就可以快速交换具体类,而无需修改使用者。因此,如果将来我想用另一个实现ISomeObject的类来替换某个对象,我可以不用碰Data.cs。这很可能是因为我对抽象的概念研究得太深入了,需要对它进行一些调整。也许我确实需要实例化Data.cs中的某个对象。请使用一个工厂(isomobjectfactory
),它接收读取器并返回一个isomobject
)。将工厂注入数据,工厂将知道如何构造isomobject
。这个答案很好,应该可以做到!非常感谢