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

如何将Autofac容器用作抽象工厂改造LetterFactory实现?

问题描述

我想要修改当前的LetterFactory实现,用容器调用替代Activator.CreateInstance,以构造函数注入的方式完全初始化Letter。我在撰写此问题前已阅读了Autofac的注册文档和委托工厂文档,甚至相关Stack Overflow帖子,但仍未找到思路。

补充说明

  1. IDocumentServicesCore是一个聚合根。
  2. 所有Letter都使用LetterTypeAttribute特性修饰(数量多达数百个)。
  3. 该LetterFactory本身已在容器中注册。

当前LetterFactory代码:

public class LetterFactory : ILetterFactory { 
    private readonly IDocumentServicesCore _documentServicesCore; 

    public LetterFactory(IDocumentServicesCore documentServicesCore) { 
        _documentServicesCore = documentServicesCore; 
    } 

    public LetterBase Create(int letterId) { 
        if (letterId <= 0) { 
            throw new ArgumentOutOfRangeException(nameof(letterId)); 
        } 

        List<Type> types = typeof(LetterBase).Assembly.GetTypes() 
            .Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(LetterBase))) 
            .ToList(); 

        LetterBase letter = null; 
        foreach(Type type in types) { 
            LetterTypeAttribute attribute = type.GetCustomAttributes<LetterTypeAttribute>().First(); 
            if (!attribute.LetterId.Contains(letterId)) { 
                continue; 
            } 

            letter = Activator.CreateInstance(type, _documentServicesCore) as LetterBase; 
            break; 
        } 

        if (letter != null) { 
            return letter; 
        } 

        string message = $"Could not find a LetterBase to create for id {letterId}."; 
        throw new NotSupportedException(message); 
    } 
}

更新1
问题似乎源于Letter本身未注册,如何利用收集Letter的LINQ代码批量注册这些类型?


解决方案

我来帮你梳理下解决思路,分两步走就能搞定:先批量注册所有Letter类型,再改造Factory借助容器来创建实例。

第一步:批量注册所有Letter类型

你可以在Autofac容器构建阶段,用你已经写好的LINQ逻辑找出所有Letter子类,然后批量注册它们。这样容器就能识别这些类型,自动处理它们的构造函数注入需求。

示例代码如下:

var builder = new ContainerBuilder();

// 注册聚合根IDocumentServicesCore
builder.RegisterType<DocumentServicesCore>().As<IDocumentServicesCore>();

// 批量注册所有LetterBase的非抽象子类
var letterTypes = typeof(LetterBase).Assembly.GetTypes()
    .Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(LetterBase)));

foreach (var type in letterTypes)
{
    // 注册每个Letter类型,Autofac会自动处理构造函数依赖注入
    builder.RegisterType(type).AsSelf();
}

// 注册LetterFactory本身
builder.RegisterType<LetterFactory>().As<ILetterFactory>();

var container = builder.Build();

第二步:改造LetterFactory,用容器解析替代Activator.CreateInstance

现在需要给LetterFactory注入ILifetimeScope(Autofac的生命周期范围对象),通过它来解析对应的Letter实例——这样就不需要手动传_documentServicesCore了,容器会自动注入所有构造函数依赖。

同时我给你加了个性能优化:提前缓存Letter类型和LetterId的映射,避免每次创建实例都重复扫描反射,毕竟你有几百个Letter类型,重复扫描太浪费资源。

改造后的Factory代码:

public class LetterFactory : ILetterFactory 
{ 
    private readonly ILifetimeScope _lifetimeScope;
    // 提前缓存LetterId与对应类型的映射,提升性能
    private readonly Dictionary<int, Type> _letterTypeMap;

    public LetterFactory(ILifetimeScope lifetimeScope) 
    { 
        _lifetimeScope = lifetimeScope;
        // 初始化类型映射缓存
        _letterTypeMap = typeof(LetterBase).Assembly.GetTypes()
            .Where(t => !t.IsAbstract && t.IsSubclassOf(typeof(LetterBase)))
            .SelectMany(t => 
            {
                var attribute = t.GetCustomAttributes<LetterTypeAttribute>().First();
                return attribute.LetterId.Select(id => new { Id = id, Type = t });
            })
            .ToDictionary(x => x.Id, x => x.Type);
    } 

    public LetterBase Create(int letterId) 
    { 
        if (letterId <= 0) { 
            throw new ArgumentOutOfRangeException(nameof(letterId)); 
        } 

        if (!_letterTypeMap.TryGetValue(letterId, out var letterType))
        {
            string message = $"Could not find a LetterBase to create for id {letterId}.";
            throw new NotSupportedException(message);
        }

        // 用Autofac的生命周期范围解析实例,自动处理所有构造函数注入
        return _lifetimeScope.Resolve(letterType) as LetterBase;
    } 
}

额外注意点

  • 注入ILifetimeScope而非直接注入IContainer是Autofac的最佳实践,避免持有根容器导致的内存泄漏问题,同时能利用当前的生命周期范围管理实例的生命周期。
  • 缓存映射字典后,每次创建实例只需查字典,性能比原来每次扫描反射提升不少,尤其适合你有大量Letter类型的场景。

这样改造后,所有Letter的构造函数依赖都会由Autofac自动注入,完全替代了Activator.CreateInstance的手动传参方式,也解决了批量注册的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:38:15