C# 使用贫血域模型的服务之间的循环引用

C# 使用贫血域模型的服务之间的循环引用,c#,dependency-injection,circular-dependency,anemic-domain-model,C#,Dependency Injection,Circular Dependency,Anemic Domain Model,我正在从事一个复杂的业务项目。 考虑两类:会计服务和学校服务 我正在使用Unity和Web API的依赖项解析器在构造函数中实现依赖项注入 public class SDPContext : ISDPContext { private ITypeResolver _typeResolver; public Account CurrentUser { get; set; } public IAccountService AccountService {

我正在从事一个复杂的业务项目。 考虑两类:会计服务和学校服务

我正在使用Unity和Web API的依赖项解析器在构造函数中实现依赖项注入

public class SDPContext : ISDPContext
{
    private ITypeResolver _typeResolver;

    public Account CurrentUser { get; set; }

    public IAccountService AccountService
    {
        get
        {
            // lazy load the account service
        }
    }

    public ISchoolService SchoolService
    {
        get
        {
            // lazy load the schoolservice
        }
    }

    public SDPContext(ITypeResolver typeResolver)
    {
        this._typeResolver = typeResolver;
    }
}

public class ServiceBase
{
    public ISDPContext CurrentContext { get; set; }

    public ServiceBase(ISDPContext context)
    {
        this.CurrentContext = context;
    }
}

public class AccountService : ServiceBase, IAccountService
{
    public AccountService(ISDPContext context) : base(context)
    {

    }

    public bool ResetAccount(int accountId)
    {
        // use base.Context.SchoolService to access the school business
    }
}

public class SchoolService : ServiceBase, ISchoolService
{
    public SchoolService(ISDPContext context) : base(context)
    {
        //this._accountService = accountService;
    }

    public void RenewRegistration(int accountId)
    {
        // use the base.Context.Account service to access the account service
    }
}
学校服务在某些方法中使用帐户服务,帐户服务也使用学校服务。所有这些都是项目业务所必需的。这将导致循环依赖,并且不可能将方法从一个类移动到另一个类

你能提供一些关于如何解决这个问题的想法吗

以下是一个例子:

public class SchoolBLC : ISchoolBLC
{
    public School GetSchool(int schoolId)
    {
        ...
    }

    public bool RenewRegistration(int accountId)
    {
        bool result = true;

        IAccountBLC accountBLC = new AccountBLC();
        // check some properties related to the account to decide if the account can be renewed
        // ex : the account should not be 5 years old
        // check the account created date and do renewal

        return result;
    }
}

public class AccountBLC : IAccountBLC
{
    public void ResetAccount(int accountId)
    {
        ISchoolBLC schoolBLC = new SchoolBLC();
        School accountSchool = schoolBLC

        // get the school related to the account to send a notification 
        // and tell the school that the user has reset his account
        // reset account and call the school notification service
    }

    public Account GetAccount(int accountId)
    {
        ...
    }
}

这两个类相互引用,这是项目中70%的BLC的情况。

如果你必须这样做,你可以有一个接口来执行你的IoC逻辑,并将其解析为一个封装Unity解析的实现,例如

public interface ITypeResolver
{
    T Resolve<T>();
}
公共接口ITypeResolver
{
T解析();
}
然后,您可以将该接口传递给构造函数中的两个服务,并在使用另一个服务之前在构造函数外部使用它来延迟解析该服务

public class SDPContext : ISDPContext
{
    private ITypeResolver _typeResolver;

    public Account CurrentUser { get; set; }

    public IAccountService AccountService
    {
        get
        {
            // lazy load the account service
        }
    }

    public ISchoolService SchoolService
    {
        get
        {
            // lazy load the schoolservice
        }
    }

    public SDPContext(ITypeResolver typeResolver)
    {
        this._typeResolver = typeResolver;
    }
}

public class ServiceBase
{
    public ISDPContext CurrentContext { get; set; }

    public ServiceBase(ISDPContext context)
    {
        this.CurrentContext = context;
    }
}

public class AccountService : ServiceBase, IAccountService
{
    public AccountService(ISDPContext context) : base(context)
    {

    }

    public bool ResetAccount(int accountId)
    {
        // use base.Context.SchoolService to access the school business
    }
}

public class SchoolService : ServiceBase, ISchoolService
{
    public SchoolService(ISDPContext context) : base(context)
    {
        //this._accountService = accountService;
    }

    public void RenewRegistration(int accountId)
    {
        // use the base.Context.Account service to access the account service
    }
}

这样,当两个服务都初始化时,它们将不会直接依赖于另一个服务,只有在
ITypeResolver
上,我将按照@KMoussa的建议进行操作,但需要进行一些修改:

项目使用的是贫血模型,因此我将使用上下文模式延迟加载和创建任何服务,并且上下文将作为参数传递给服务构造函数

public class SDPContext : ISDPContext
{
    private ITypeResolver _typeResolver;

    public Account CurrentUser { get; set; }

    public IAccountService AccountService
    {
        get
        {
            // lazy load the account service
        }
    }

    public ISchoolService SchoolService
    {
        get
        {
            // lazy load the schoolservice
        }
    }

    public SDPContext(ITypeResolver typeResolver)
    {
        this._typeResolver = typeResolver;
    }
}

public class ServiceBase
{
    public ISDPContext CurrentContext { get; set; }

    public ServiceBase(ISDPContext context)
    {
        this.CurrentContext = context;
    }
}

public class AccountService : ServiceBase, IAccountService
{
    public AccountService(ISDPContext context) : base(context)
    {

    }

    public bool ResetAccount(int accountId)
    {
        // use base.Context.SchoolService to access the school business
    }
}

public class SchoolService : ServiceBase, ISchoolService
{
    public SchoolService(ISDPContext context) : base(context)
    {
        //this._accountService = accountService;
    }

    public void RenewRegistration(int accountId)
    {
        // use the base.Context.Account service to access the account service
    }
}

你能举个例子说明你的项目中的这种循环依赖性吗?听起来像是一个糟糕的设计。。。我会把普通的东西发到第三个服务。这将解决循环依赖。DI引擎通常会在循环引用上抛出异常。@大锤更切中要害。即使没有DI,您如何解决这个问题?DI并不是神奇的,如果你没有它就做不到,那么你就不能用它来做。我想补充一下SledgeHammer的答案。你的问题是你有两个紧密耦合的类。如果它们是70%耦合的,这不意味着它们是相同的代码单元吗?考虑OOP的核心原理,封装;您应该尽可能少地公开功能。如果有两个类的方法只由彼此调用,则不进行封装。这意味着,您的代码不是面向对象的。@Aron。不,我不是。我的建议是,如果接口A&B有很多公共代码/功能,那么它要么在基类中,要么分为接口C。然后A&B使用接口C而不是B&A,你就打破了循环引用。