C# 依赖注入体系结构设计-服务类循环引用
我有以下服务类别:C# 依赖注入体系结构设计-服务类循环引用,c#,dependency-injection,inversion-of-control,circular-dependency,C#,Dependency Injection,Inversion Of Control,Circular Dependency,我有以下服务类别: public class JobService { private UserService us; public JobService (UserService us) { this.us = us; } public void addJob(Job job) { // needs to make a call to user service to update some user info // similar dependenc
public class JobService {
private UserService us;
public JobService (UserService us) {
this.us = us;
}
public void addJob(Job job) {
// needs to make a call to user service to update some user info
// similar dependency to the deleteUser method
}
}
public class UserService {
private JobService js;
public UserService(JobService js) {
this.js = js;
}
public void deleteUser(User u) {
using (TransactionScope scope = new TransactionScope()) {
List<IJob> jobs = jobService.findAllByUser(u.Id);
foreach (IJob job in jobs) {
js.deleteJob(job);
}
userDao.delete(user);
scope.Complete();
}
}
}
公共类就业服务{
私人用户服务;
公共就业服务(UserService us){
this.us=us;
}
公共无效添加作业(作业作业){
//需要致电用户服务以更新某些用户信息
//与deleteUser方法类似的依赖关系
}
}
公共类用户服务{
私人就业服务;
公共用户服务(JobService js){
this.js=js;
}
公共用户(用户u){
使用(TransactionScope范围=新TransactionScope()){
List jobs=jobService.findallbyser(u.Id);
foreach(作业中的IJob作业){
js.deleteJob(job);
}
删除(用户);
scope.Complete();
}
}
}
这些服务类中的每一个都被IoC容器实例化了,这并不是一个功能问题,但我觉得这种方法有一个潜在的设计缺陷,我想知道是否有一种替代方法更有意义。这在Autofac中不起作用。请参阅文档的第节 构造函数/构造函数依赖关系两种类型 不支持构造函数依赖项。你会得到一个例外 当您尝试解析以这种方式注册的类型时 您可能会使用(
Func
,Lazy
)来打破这种循环
<>你的代码有点太一般,无法找到一个合适的解决方案,但是不管你使用的IoC容器是什么,你都应该考虑改变依赖的方向。
public class JobService {
private UserService us;
public JobService (UserService us) {
this.us = us;
}
public void addJob(Job job) {
// needs to make a call to user service to update some user info
}
}
public class UserService {
private JobService js;
public UserService(Func<JobService> jsFactory) {
this.js = jsFactory(this);
}
public void deleteUser(User u) {
// needs to call the job service to delete all the user's jobs
}
}
公共类就业服务{
私人用户服务;
公共就业服务(UserService us){
this.us=us;
}
公共无效添加作业(作业作业){
//需要致电用户服务以更新某些用户信息
}
}
公共类用户服务{
私人就业服务;
公共用户服务(Func jsFactory){
this.js=jsFactory(this);
}
公共用户(用户u){
//需要调用作业服务来删除用户的所有作业
}
}
或者,在您的示例中,您可以移动deleteUser
并创建一个方法,删除作业服务上的所有作业,而不是使用id引用用户。这通过使用id打破了依赖关系
另一种选择是将作业服务作为参数传递给
deleteUser
这在Autofac中不起作用。请参阅文档的第节
构造函数/构造函数依赖关系两种类型
不支持构造函数依赖项。你会得到一个例外
当您尝试解析以这种方式注册的类型时
您可能会使用(Func
,Lazy
)来打破这种循环
<>你的代码有点太一般,无法找到一个合适的解决方案,但是不管你使用的IoC容器是什么,你都应该考虑改变依赖的方向。
public class JobService {
private UserService us;
public JobService (UserService us) {
this.us = us;
}
public void addJob(Job job) {
// needs to make a call to user service to update some user info
}
}
public class UserService {
private JobService js;
public UserService(Func<JobService> jsFactory) {
this.js = jsFactory(this);
}
public void deleteUser(User u) {
// needs to call the job service to delete all the user's jobs
}
}
公共类就业服务{
私人用户服务;
公共就业服务(UserService us){
this.us=us;
}
公共无效添加作业(作业作业){
//需要致电用户服务以更新某些用户信息
}
}
公共类用户服务{
私人就业服务;
公共用户服务(Func jsFactory){
this.js=jsFactory(this);
}
公共用户(用户u){
//需要调用作业服务来删除用户的所有作业
}
}
或者,在您的示例中,您可以移动deleteUser
并创建一个方法,删除作业服务上的所有作业,而不是使用id引用用户。这通过使用id打破了依赖关系
另一种选择是将作业服务作为参数传递给
deleteUser
您遇到的问题实际上与DI容器的限制无关,但这是一个一般性问题。即使没有任何容器,也不可能创建这些类型:
var job = new JobService([what goes here???]);
var user = new UserService(job);
因此,一般的答案是将其中一个依赖项提升到属性。这将打破依赖循环:
var job = new JobService();
var user = new UserService(job);
// Use property injection
job.User = user;
但是,请防止使用超出严格要求的属性。这些依赖循环应该非常罕见,这使得将类型连接在一起或验证DI配置的正确性变得更加困难。构造函数注入使这变得更容易。您遇到的问题实际上与DI容器的限制无关,但这是一个普遍的问题。即使没有任何容器,也不可能创建这些类型:
var job = new JobService([what goes here???]);
var user = new UserService(job);
因此,一般的答案是将其中一个依赖项提升到属性。这将打破依赖循环:
var job = new JobService();
var user = new UserService(job);
// Use property injection
job.User = user;
但是,请防止使用超出严格要求的属性。这些依赖循环应该非常罕见,这使得将类型连接在一起或验证DI配置的正确性变得更加困难。构造函数注入使这变得更加容易。正如有人已经指出的,问题不在于DI容器的限制,而在于您的设计 我明白了为什么您有一个单独的
UserService
和一个JobService
,其中包含彼此的引用。这是因为UserService
和JobService
都包含一些需要其他服务作为参考的逻辑(添加作业需要添加用户等)。但是,我认为您不应该从一个服务引用另一个服务。相反,您应该在服务后面有另一层抽象,这些服务将用于公共逻辑。因此,服务将包含不能(不应该)重用的逻辑,而助手将包含共享逻辑
例如:
public class UserHelper{
//add all your common methods here
}
public class JobService {
private UserHelper us;
public JobService (UserHelper us) {
this.us = us;
}
public void addJob(Job job) {
// calls helper class
}
}
public class UserService {
public UserService(UserHelper js) {
this.js = js;
}
public void deleteUser(User u) {
// calls helper class
}
}
这样,循环引用就不会有任何问题,您将有一个地方包含需要由不同服务重用的逻辑
而且,