基于类型的泛型接口依赖注入:如何注册对应具体实现?
在.NET中实现泛型文件序列化器的依赖注入方案
1. 调整泛型接口定义
首先将原有的IFileSerializer改造为泛型接口,明确绑定特定的IStorableFile派生类型:
public interface IFileSerializer<T> where T : IStorableFile { void Serialize(T file, string path); T Deserialize(string path); }
对应修改具体序列化器的实现,让它们实现对应类型的泛型接口:
public class FileTypeASerializer : IFileSerializer<FileTypeA> { public void Serialize(FileTypeA file, string path) { // 针对FileTypeA的序列化逻辑 } public FileTypeA Deserialize(string path) { // 针对FileTypeA的反序列化逻辑 } } public class FileTypeBSerializer : IFileSerializer<FileTypeB> { // 同理实现FileTypeB的序列化/反序列化逻辑 }
2. 在DI容器中注册泛型服务
在项目的DI配置(比如Program.cs)中,逐个注册文件类型与对应序列化器的映射:
// 注册具体的泛型序列化器实现 builder.Services.AddScoped<IFileSerializer<FileTypeA>, FileTypeASerializer>(); builder.Services.AddScoped<IFileSerializer<FileTypeB>, FileTypeBSerializer>();
3. 处理未注册类型的友好错误
为了在注入未注册的IFileSerializer<T>时抛出明确错误,我们可以实现一个兜底的泛型序列化器,当容器找不到对应类型的实现时自动使用它:
public class UnregisteredFileSerializer<T> : IFileSerializer<T> where T : IStorableFile { public void Serialize(T file, string path) { throw new NotSupportedException($"未注册针对类型 {typeof(T).Name} 的文件序列化器,请先在DI容器中注册对应的IFileSerializer<{typeof(T).Name}>实现。"); } public T Deserialize(string path) { throw new NotSupportedException($"未注册针对类型 {typeof(T).Name} 的文件序列化器,请先在DI容器中注册对应的IFileSerializer<{typeof(T).Name}>实现。"); } }
然后在DI配置中,在注册完所有具体实现后,添加这个兜底的泛型服务注册:
// 注册泛型兜底服务,当找不到对应T的实现时触发 builder.Services.AddScoped(typeof(IFileSerializer<>), typeof(UnregisteredFileSerializer<>));
4. 消费类直接注入泛型服务
按照你提供的示例,消费类可以直接注入指定类型的泛型序列化器,DI容器会自动匹配对应的实现:
public class MyConsumingClass { private readonly IFileSerializer<FileTypeA> _serializerForTypeA; private readonly IFileSerializer<FileTypeB> _serializerForTypeB; public MyConsumingClass( IFileSerializer<FileTypeA> serializerForTypeA, IFileSerializer<FileTypeB> serializerForTypeB) { _serializerForTypeA = serializerForTypeA; _serializerForTypeB = serializerForTypeB; } public void ProcessFiles() { // 使用_serializerForTypeA处理FileTypeA文件 // 使用_serializerForTypeB处理FileTypeB文件 } }
可选:动态获取序列化器(运行时类型未知场景)
如果需要在运行时根据IStorableFile的动态类型获取序列化器,可以实现一个工厂类:
public class FileSerializerFactory { private readonly IServiceProvider _serviceProvider; public FileSerializerFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } // 泛型版本,用于编译时已知类型的场景 public IFileSerializer<T> GetSerializer<T>() where T : IStorableFile { var serializer = _serviceProvider.GetService<IFileSerializer<T>>(); if (serializer is UnregisteredFileSerializer<T>) { throw new InvalidOperationException($"未找到类型 {typeof(T).Name} 的序列化器注册"); } return serializer ?? throw new InvalidOperationException($"无法获取类型 {typeof(T).Name} 的序列化器"); } // 非泛型版本,用于运行时动态类型的场景 public object GetSerializer(Type fileType) { var serializerType = typeof(IFileSerializer<>).MakeGenericType(fileType); var serializer = _serviceProvider.GetService(serializerType); if (serializer?.GetType().GetGenericTypeDefinition() == typeof(UnregisteredFileSerializer<>)) { throw new InvalidOperationException($"未找到类型 {fileType.Name} 的序列化器注册"); } return serializer ?? throw new InvalidOperationException($"无法获取类型 {fileType.Name} 的序列化器"); } }
注册这个工厂到DI容器:
builder.Services.AddScoped<FileSerializerFactory>();
消费类可以通过工厂动态获取序列化器:
public class DynamicFileProcessor { private readonly FileSerializerFactory _serializerFactory; public DynamicFileProcessor(FileSerializerFactory serializerFactory) { _serializerFactory = serializerFactory; } public void ProcessDynamicFile(IStorableFile file, string path) { var serializer = _serializerFactory.GetSerializer(file.GetType()); // 通过反射调用序列化方法 var serializeMethod = serializer.GetType().GetMethod(nameof(IFileSerializer<IStorableFile>.Serialize)); serializeMethod?.Invoke(serializer, new[] { file, path }); } }
内容的提问来源于stack exchange,提问作者Bassinator
相关产品推荐
相关产品推荐

