【发布时间】:2014-05-10 16:30:25
【问题描述】:
我认为人们普遍认为跟随是不好的
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 或在需要时创建新的 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 配置可以使用 mock 设置所有内容 - 而且很容易使用。
编辑:
我会尝试用一个不同的例子来澄清我的困惑。假设我有一个带有 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 控制器来解析实例依赖关系,还是有处理这些情况的首选方法?还是我只是做错了什么……?
【问题讨论】:
-
回答这个问题有点困难,因为这两个例子都有内置的问题:UnitOfWork 的第一个例子有一个问题(正如你已经指出的那样)它没有做 任何东西;它完全是多余的,可以从您的代码库中删除。第二个示例带有内置问题(由于框架限制),
Form必须 具有默认构造函数。但是,总有办法解决这些问题。 Composition Root 是您可能会发现有用的一个核心概念。 -
你说话的方式我知道你会真正受益(就像我以外的许多其他人一样)尽快购买 manning.com/seemann(并在你阅读 Mark 投票最多的答案时)等待它到达)
-
看起来很有趣,而且物有所值——巧合的是,他实际上就住在我附近:)
标签: c# dependency-injection inversion-of-control