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

基于类型的泛型接口依赖注入:如何注册对应具体实现?

在.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 07:25:24