如何让IEnumerable<IRepository>与特定仓储接口注入同一实例?
问题描述
现有仓储接口与实现类结构如下:
public interface IRepository { public Task PreLoadData(); } public interface IUserRepository : IRepository { public List<User> Users { get; } // 其他实例专属方法 } public class UserRepository : IUserRepository { public List<User> Users { get; private set; } public async Task PreLoadData() { Users = await GetUsers(); } }
同时需要通过DataPreLoader统一预加载数据:
public class DataPreLoader { private IEnumerable<IRepository> _repositories; public DataPreLoader(IEnumerable<IRepository> repositories) { _repositories = repositories; } public async Task PreloadAllData() { foreach(var repository in _repositories) { await repository.PreLoadData(); } } }
遇到的问题:
- 若使用
services.AddScoped<IRepository, UserRepository>()注册,IEnumerable<IRepository>与IUserRepository能被注入,但二者是不同实例:调用IEnumerable<IRepository>中实例的PreLoadData()后,后续注入的IUserRepository并未加载数据。 - 若使用
services.AddScoped<IUserRepository, UserRepository>()注册,IEnumerable<IRepository>为空,无法通过DataPreLoader预加载数据。
需要实现的目标:确保IEnumerable<IRepository>接收的实例与注入IUserRepository时的实例为同一个。
解决方案
要让两个接口共享同一个实例,需在DI容器中明确将IRepository和IUserRepository关联到同一个UserRepository实例,具体有两种实现方式:
方式1:先注册实现类,再映射接口
services.AddScoped<UserRepository>(); services.AddScoped<IRepository>(sp => sp.GetRequiredService<UserRepository>()); services.AddScoped<IUserRepository>(sp => sp.GetRequiredService<UserRepository>());
这种方式下,DI容器会先创建UserRepository的Scoped实例,后续无论是请求IRepository、IUserRepository还是IEnumerable<IRepository>,都会返回这个已创建的实例(在当前Scoped生命周期内)。
方式2:基于已注册的接口映射
services.AddScoped<IUserRepository, UserRepository>() .AddScoped<IRepository>(sp => sp.GetRequiredService<IUserRepository>());
先完成IUserRepository到UserRepository的注册,再将IRepository指向已注册的IUserRepository实例,确保两个接口共享同一个实例。
原理说明
- 直接单独注册某一个接口时,DI容器会将每个接口视为独立的服务类型,即使它们指向同一个实现类,也会创建不同的实例。
- 通过显式指定实例来源(从容器中获取已注册的实现类/接口实例),可以强制多个接口共享同一个实例,解决预加载后数据不共享的问题。
内容的提问来源于stack exchange,提问作者Nijenhof
相关产品推荐
相关产品推荐

