在 .NET 中,使用注入解决这种必要的循环依赖关系的最佳方法是什么?

问题描述 投票:0回答:2

这是我的三个班级示例。有几十个这样的适配器,一个用于我的数据集中的每个实体,它们处理该实体的不同协议之间的所有转换。在我想要水合物体之前效果很好。在此示例中,客户端可能有一个分配给他们的代理。代理可能是我们系统中的用户,因此具有用户对象。用户可以是客户端用户,因此可以有一个分配给他们的客户端。这些东西在数据中不是循环的,但它们的类型是

ClientAdapter.cs

public interface IClientAdapter :
    IModelAdapter<ClientModel, ClientDatabaseModel, ClientResponseModel>
{
}

public class ClientAdapter : IClientAdapter
{ 
    IAgentAdapter _agentAdapter;

    public ClientAdapter(IAgentAdapter agentAdapter)
    {
        _agentAdapter = agentAdapter; 
    }

    public ClientResponseModel convertFromModelToResponseModel(ClientModel model)
    {
        ClientResponseModel responseModel = new ClientResponseModel()
        {
            Id = model.Id, 
            AgentId = model.AgentId,
            Agent = model.Agent == null
                ? null
                : this._agentAdapter.convertFromModelToResponseModel(model.Agent), 
            Name = model.Name
        };
 
        return responseModel;
    }
}

代理适配器.cs

public interface IAgentAdapter :
    IModelAdapter<AgentModel, AgentDatabaseModel, AgentResponseModel>
{
}

public class AgentAdapter : IAgentAdapter
{ 
    IUserAdapter _userAdapter;

    public AgentAdapter(IUserAdapter userAdapter)
    {
        _userAdapter = userAdapter; 
    }

    public AgentResponseModel convertFromModelToResponseModel(AgentModel model)
    {
        AgentResponseModel responseModel = new AgentResponseModel()
        {
            Id = model.Id, 
            UserId = model.UserId,
            User = model.User == null
                ? null
                : this._userAdapter.convertFromModelToResponseModel(model.User), 
            Name = model.Name
        };
 
        return responseModel;
    }
}

用户适配器.cs

public interface IUserAdapter :
    IModelAdapter<UserModel, UserDatabaseModel, UserResponseModel> 
{
}

public class UserAdapter : IUserAdapter
{ 
    IClientAdapter _clientAdapter;

    public UserAdapter(IClientAdapter clientAdapter)
    {
        _clientAdapter = clientAdapter; 
    }

    public UserResponseModel convertFromModelToResponseModel(UserModel model)
    {
        UserResponseModel responseModel = new UserResponseModel()
        {
            Id = model.Id, 
            ClientId = model.ClientId,
            Client = model.UserClient == null
               ? null
               : this._clientAdapter.convertFromModelToResponseModel(model.Client), 
            Name = model.Name
        };
 
        return responseModel;
    }
}

如您所见,类之间必然会互相调用。不存在循环问题,因为它们可以具有非空值的唯一方法是通过显式请求,因此实际上主要问题是构建器抱怨注入循环引用,并且可能需要在注入级别进行更改,并且我不太了解/了解 .NET 的注入来修复它。

这是我围绕这三个类的注入,非常简单:

var builder = WebApplication.CreateBuilder(args);

// add services to DI container
{
    var services = builder.Services;

    services.AddScoped<IAgentAdapter, AgentAdapter>();
    services.AddScoped<IClientAdapter, ClientAdapter>();
    services.AddScoped<IUserAdapter, UserAdapter>();
}

var app = builder.Build();

这默认使用我的定义来完成系统,并且还允许我通过随意覆盖我的实现来进行单元测试,但这也是有关循环依赖的运行时错误的根源。苏?

c# .net dependency-injection circular-dependency
2个回答
1
投票

如果无法消除循环依赖,一种方法是注入

Lazy<T>
。如果这不起作用,您可以注入
IServiceProvider
并显式解析依赖类型。使用
IServiceProvider
可以被认为是一种反模式,我只会将其用作最后的手段。如果您确实使用它,请务必添加注释,以便下一个开发人员(Jr?)不会认为这是应该在任何地方使用的方法。


0
投票

我会尝试重构代码以删除循环依赖,但如果不可避免,您可以使用 Lazy<> 来声明依赖。 Autofac 支持 OTB。如果您的容器不支持,您可以查看此answer,了解轻松实现此功能的方法。

© www.soinside.com 2019 - 2024. All rights reserved.