.NET依赖注入之一个接口多个实现

编程艺术家 2024-03-17 ⋅ 19 阅读

简介

在面向对象编程中,接口是一种定义了一组方法和属性的规范。.NET框架中的依赖注入(Dependency Injection,简称DI)是一种设计模式,允许我们通过接口将依赖项注入到类中,以提高代码的可测试性和可扩展性。然而,当一个接口有多个实现时,我们可能面临一些挑战。在本篇博客中,我们将探讨如何在.NET中处理一个接口有多个实现的情况。

问题场景

假设我们正在开发一个在线书店的系统,并且我们需要实现一个用于搜索图书的功能。我们定义了一个IBookSearchService接口,并且有两个不同的实现,一个使用关键词搜索(KeywordBookSearchService),一个使用作者搜索(AuthorBookSearchService)。

public interface IBookSearchService
{
    IEnumerable<Book> Search(string query);
}

public class KeywordBookSearchService : IBookSearchService
{
    public IEnumerable<Book> Search(string query)
    {
        // 使用关键词搜索
        // ...
    }
}

public class AuthorBookSearchService : IBookSearchService
{
    public IEnumerable<Book> Search(string query)
    {
        // 使用作者搜索
        // ...
    }
}

现在的问题是,我们如何在整个应用程序中正确地将接口的每个实现注入到需要它的地方?

解决方案

.NET框架提供了一种通过依赖注入容器来管理接口和其实现之间关系的方式。我们可以使用.Net Core自带的依赖注入容器(IServiceProvider)或者第三方的容器,例如Autofac、Unity等。这里我们以.Net Core自带的容器为例。

首先,我们需要在启动类中注册我们的依赖关系。在Startup.csConfigureServices方法中,我们可以使用.AddScoped.AddTransient.AddSingleton方法将接口和它的实现关联起来。

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IBookSearchService, KeywordBookSearchService>();
    services.AddScoped<IBookSearchService, AuthorBookSearchService>();
}

这样一来,当我们在其他类中需要使用IBookSearchService的实例时,我们可以将其作为构造函数参数进行注入。

public class BookController : Controller
{
    private readonly IBookSearchService _bookSearchService;

    public BookController(IBookSearchService bookSearchService)
    {
        _bookSearchService = bookSearchService;
    }

    // ...
}

注意,使用.AddScoped方法注册多个实现时,每次注入都会创建一个新的实例。而.AddTransient方法会在每次注入时都创建一个新的实例,.AddSingleton方法则是在应用程序的生命周期中只创建一个实例。

使用特性进行注入

除了在启动类中进行注册外,我们还可以使用特性([Inject][Named])来标记需要注入的属性或构造函数参数,并使用IoC容器进行自动注入。

public class BookController : Controller
{
    [Inject]
    [Named("KeywordBookSearchService")]
    private readonly IBookSearchService _keywordBookSearchService;

    [Inject]
    [Named("AuthorBookSearchService")]
    private readonly IBookSearchService _authorBookSearchService;

    public BookController()
    {
        // 无参构造函数,通过属性进行注入
    }

    public BookController([Inject][Named("KeywordBookSearchService")] IBookSearchService keywordBookSearchService,
                          [Inject][Named("AuthorBookSearchService")] IBookSearchService authorBookSearchService)
    {
        _keywordBookSearchService = keywordBookSearchService;
        _authorBookSearchService = authorBookSearchService;
    }

    // ...
}

总结

在本篇博客中,我们讨论了在.NET中处理一个接口有多个实现的情况下如何使用依赖注入。通过使用.NET Core自带的依赖注入容器,我们可以非常方便地将接口的每个实现注入到需要它的地方。使用依赖注入可以帮助我们提高代码的可测试性、可扩展性和可维护性。

参考资料


全部评论: 0

    我有话说: