You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core 如何调用泛型IAppRepository<T>所有实现执行批量删除操作

解决方案

完全可以实现批量调用所有已注册仓储的需求,不需要逐个按事件类型调用,以下提供两种可落地的实现方案:


方案1:新增非泛型基接口(最推荐,性能最优)

通过引入非泛型的基接口解决泛型类型不能直接统一遍历的问题,改动量极小:

  1. 定义非泛型基接口
public interface IAppRepository
{
    Task<IReadOnlyList<IAppEvent>> GetAllEventsByDateTimeAsync(DateTime eventsBeforeDate);
    Task DeleteEventAsync(string internalRequestId);
}
  1. 调整原有泛型接口继承非泛型基接口
public interface IAppRepository<T> : IAppRepository where T: IAppEvent
{
    // 保留原有泛型方法
    new Task<IReadOnlyList<T>> GetAllEventsByDateTimeAsync(DateTime eventsBeforeDate);
}
  1. 在仓储实现类中显式实现非泛型接口方法(以SampleRepo为例)
public class SampleRepo : IAppRepository<SampleEvent>
{
    // 原有泛型方法逻辑不变
    public Task<IReadOnlyList<SampleEvent>> GetAllEventsByDateTimeAsync(DateTime eventsBeforeDate)
    {
        // 原有实现
    }

    // 新增非泛型方法的显式实现
    async Task<IReadOnlyList<IAppEvent>> IAppRepository.GetAllEventsByDateTimeAsync(DateTime eventsBeforeDate)
    {
        var result = await GetAllEventsByDateTimeAsync(eventsBeforeDate);
        return result.ToList();
    }

    // Delete方法参数和非泛型定义完全一致,不需要额外修改
    public Task DeleteEventAsync(string internalRequestId)
    {
        // 原有实现
    }
}
  1. 实现批量获取仓储的方法
public IEnumerable<IAppRepository> GetAllRepos(IServiceProvider serviceProvider)
{
    // 扫描所有实现IAppEvent的类型
    var eventTypes = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(ass => ass.GetTypes())
        .Where(t => typeof(IAppEvent).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

    foreach (var eventType in eventTypes)
    {
        var genericRepoType = typeof(IAppRepository<>).MakeGenericType(eventType);
        var repoInstance = serviceProvider.GetService(genericRepoType);
        if (repoInstance != null)
        {
            yield return (IAppRepository)repoInstance;
        }
    }
}
  1. 最终调用逻辑(注意修正原有异步等待和变量名问题)
var cutoffTime = DateTime.Now;
foreach (var repo in GetAllRepos(serviceProvider))
{
    var oldEvents = await repo.GetAllEventsByDateTimeAsync(cutoffTime);
    foreach (var appEvent in oldEvents)
    {
        await repo.DeleteEventAsync(appEvent.InternalRequestId);
    }
}

方案2:纯反射实现(无需修改原有代码)

如果不想改动现有接口和实现定义,可以直接用反射调用对应方法,零侵入现有逻辑:

public async Task DeleteAllOldEvents(IServiceProvider serviceProvider, DateTime cutoffTime)
{
    // 扫描所有事件类型
    var eventTypes = AppDomain.CurrentDomain.GetAssemblies()
        .SelectMany(ass => ass.GetTypes())
        .Where(t => typeof(IAppEvent).IsAssignableFrom(t) && !t.IsInterface && !t.IsAbstract);

    foreach (var eventType in eventTypes)
    {
        // 解析对应泛型仓储
        var genericRepoType = typeof(IAppRepository<>).MakeGenericType(eventType);
        var repo = serviceProvider.GetService(genericRepoType);
        if (repo == null) continue;

        // 反射调用查询方法
        var getMethod = genericRepoType.GetMethod(nameof(IAppRepository<IAppEvent>.GetAllEventsByDateTimeAsync));
        var getTask = (Task)getMethod.Invoke(repo, new object[] { cutoffTime });
        await getTask;

        // 读取查询结果
        var result = (IEnumerable<IAppEvent>)getTask.GetType().GetProperty("Result").GetValue(getTask);

        // 反射调用删除方法
        var deleteMethod = genericRepoType.GetMethod(nameof(IAppRepository<IAppEvent>.DeleteEventAsync));
        foreach (var appEvent in result)
        {
            var deleteTask = (Task)deleteMethod.Invoke(repo, new object[] { appEvent.InternalRequestId });
            await deleteTask;
        }
    }
}

注意事项

  • 原示例代码中event是C#关键字,不能作为变量名使用,建议替换为appEvent等自定义名称
  • 所有异步方法必须添加await关键字,否则会出现任务未执行完成就进入后续逻辑的问题
  • 如果事件类型定义在多个程序集中,需要调整反射扫描的程序集范围避免漏扫

内容的提问来源于stack exchange,提问作者Roni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 10:27:03