.NET运行时泛型依赖注入:根据FileType动态调用ICleanerService
解决方案
1. FileType与DTO/DTOMap的映射
直接用类型字典建立枚举与对应类型的关联,无需给DTO额外定义接口,避免冗余设计。可以选择静态字典或注入单例两种方式:
方式1:静态字典(简单场景)
// 可放在ExcelService内部或单独的配置类中 private static readonly Dictionary<FileType, (Type DtoType, Type MapType)> _typeMappings = new() { { FileType.SMALL_EXCEL, (typeof(DTO), typeof(DTOMap)) }, { FileType.LARGE_EXCEL, (typeof(DTO2), typeof(DTO2Map)) } };
方式2:注入单例字典(灵活扩展场景)
如果后续需要从配置文件或数据库读取映射关系,可将字典注册为单例服务:
// Program.cs 中注册 var typeMappings = new Dictionary<FileType, (Type DtoType, Type MapType)> { { FileType.SMALL_EXCEL, (typeof(DTO), typeof(DTOMap)) }, { FileType.LARGE_EXCEL, (typeof(DTO2), typeof(DTO2Map)) } }; services.AddSingleton(typeMappings);
2. 运行时获取对应ICleanerService并调用方法
通过IServiceProvider结合反射,动态构造泛型服务类型并调用方法:
步骤1:ExcelService注入依赖
public class ExcelService : IExcelService { private readonly IServiceProvider _serviceProvider; private readonly Dictionary<FileType, (Type DtoType, Type MapType)> _typeMappings; // 注入服务提供器和映射字典(如果用静态字典则无需注入后者) public ExcelService(IServiceProvider serviceProvider, Dictionary<FileType, (Type, Type)> typeMappings) { _serviceProvider = serviceProvider; _typeMappings = typeMappings; }
步骤2:动态调用CleanObject方法
public async Task<bool> TransformExcel(FileType fileType, string path) { if (!_typeMappings.TryGetValue(fileType, out var types)) { throw new ArgumentException($"不支持的文件类型:{fileType}"); } // 构造泛型服务类型:ICleanerService<T, V> var cleanerServiceType = typeof(ICleanerService<,>).MakeGenericType(types.DtoType, types.MapType); // 从容器获取服务实例 var cleanerService = _serviceProvider.GetService(cleanerServiceType); if (cleanerService == null) { throw new InvalidOperationException($"未注册对应的ICleanerService:{cleanerServiceType.FullName}"); } // 调用异步的CleanObject方法 var cleanMethod = cleanerServiceType.GetMethod(nameof(ICleanerService<object, object>.CleanObject)); var taskResult = (Task<List<object>>)cleanMethod.Invoke(cleanerService, new object[] { path }); var resultList = await taskResult; // 根据业务需求返回结果,示例为返回是否有清理后的数据 return resultList != null && resultList.Count > 0; } }
优化:封装通用调用逻辑
如果多处需要动态调用泛型服务,可封装工具类减少重复代码:
public static class CleanerServiceHelper { public static async Task<List<object>> CleanAsync(this IServiceProvider provider, FileType fileType, string path, Dictionary<FileType, (Type, Type)> mappings) { if (!mappings.TryGetValue(fileType, out var types)) throw new ArgumentException($"不支持的文件类型:{fileType}"); var serviceType = typeof(ICleanerService<,>).MakeGenericType(types.Item1, types.Item2); var service = provider.GetService(serviceType) ?? throw new InvalidOperationException($"未注册服务:{serviceType}"); var method = serviceType.GetMethod(nameof(ICleanerService<object, object>.CleanObject)) ?? throw new MissingMethodException("找不到CleanObject方法"); return await (Task<List<object>>)method.Invoke(service, new[] { path }); } }
之后ExcelService可简化为:
public async Task<bool> TransformExcel(FileType fileType, string path) { var result = await _serviceProvider.CleanAsync(fileType, path, _typeMappings); return result != null && result.Count > 0; }
内容的提问来源于stack exchange,提问作者Gerard
相关产品推荐
相关产品推荐

