son*_*ard 5 c# dependency-injection inversion-of-control
我认为普遍认为以下是不好的
public class Foo
{
    private IService _service;
    public Foo()
    {
        _service = IocContainer.Resolve<IService>();
    }
}
以下是首选(依赖注入)
public class Foo
{
    private IService _service;
    public Foo(IService service)
    {
    }
}
但是现在由消费者提供服务.消费者当然也可以在构造函数中要求IService,但是当层次结构变得更深时,它似乎很烦人.在某些时候,有人需要从IoC容器请求IService - 但是什么时候......?
我工作场所的一位前同事为UoW/Repository模式编写了一个UnitOfWork类(使用Microsoft ServiceLocator):
public static UnitOfWork
{
    public static IUnitOfWork Current
    {
        get { return ServiceLocator.Current.GetInstance<IUnitOfWork>(); }
    }
    public static void Commit()
    {
        Current.Commit();
    }
    public static void Dispose()
    {
        Current.Dispose();
    }
    public static IRepository<T> GetRepository<T>() where T : class
    {
        return ServiceLocator.Current.GetInstance<IRepository>();
    }
}
并使用Ninject连接IoC,因此对IRepository的请求将找到当前的UoW或在需要时创建一个新的(如果处理当前电流).使用成为
public class MyController
{    
    public void RunTasks()
    {
        var rep = UnitOfWork.GetRepository<Tasks>();
        var newTasks = from t in rep.GetAll()
                       where t.IsCompleted == false
                       select t;
        foreach (var task in newTasks)
        {
            // Do something
        }
        UnitOfWork.Commit();
    }
}
但它确实仍然受到静态IoC(服务定位器)类的影响,但是会有更智能的解决方案吗?在这种情况下,不需要知道内部依赖性(静态类没有逻辑),并且出于测试目的,备用IoC配置可以使用模拟设置所有内容 - 并且它易于使用.
编辑:
我将试着通过一个不同的例子澄清我的困惑.假设我有一个带有MainWindow类的标准winforms应用程序.当用户单击按钮时,我需要从数据库加载一些数据,并将其传递给将处理数据的类:
public class MainWindow : Form
{
    public MainWindow()
    {
    }
    private void OnUserCalculateClick(object sender, EventArgs args)
    {
        // Get UoW to connect to DB
        // Get instance of processor
    }
}
我如何获得处理器的实例和工作单元?它可以注入表格类吗?
我想我的问题归结为:如果我在一个没有Ioc构建的类中,它可能是一个winform,一个ria服务类等. - 可以引用服务定位器/ IoC控制器来解析依赖关系的实例,还是有一种处理这些案件的首选方式?或者我只是做错了什么......?
我解决这个问题的方法是有一个UnitOfWorkFactory它有一个Create方法来创建你的UnitOfWork.
public interface IUnitOfWorkFactory
{
    IUnitOfWork Create();
}
public interface IUnitOfWork : IDisposable
{
    T GetRepository<T>();
    void Commit();
}
public class MyController
{    
    private readonly IUnitOfWorkFactory _unitOfWorkFactory;
    public MyController(IUnitOfWorkFactory unitOfWorkFactory)
    {
        _unitOfWorkFactory = unitOfWorkFactory;
    }
    public void RunTasks()
    {
        using (var unitOfWork = _unitOfWorkFactory.Create())
        {
            var rep = UnitOfWork.GetRepository<Tasks>();
            var newTasks = from t in rep.GetAll()
                           where t.IsCompleted == false
                           select t;
            foreach (var task in newTasks)
            {
                // Do something
            }               
            unitOfWork.Commit();
        }
    }
}  
拥有工厂的优点是它可以让用户(控制器)控制工作单元的创建和销毁。
这也使单元测试变得更容易,因为您不需要使用 IoC 进行测试。我也不喜欢拥有可用的全局上下文(例如UnitOfWork.Current),因为很难确定 UoW 何时将被处置或提交。
如果另一个类需要 UoW 的实例来向现有上下文添加额外的工作,您可以传入特定的实例。
| 归档时间: | 
 | 
| 查看次数: | 1347 次 | 
| 最近记录: |