You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Autofac注册阶段解析依赖?原Unity用户的迁移咨询

从Unity IOC迁移到Autofac:多实现接口的注册与工厂模式解决方案

好的,我来帮你搞定这个Unity转Autofac的问题——我之前也处理过类似的多实现接口注册+工厂注入的场景,Autofac的思路和Unity确实不一样,核心是不能在注册阶段直接Resolve,但我们可以用它的键控注册上下文解析来实现相同的效果。

第一步:用键控注册替代Unity的TypedParameter

在Unity里你通过TypedParameter来区分不同的IQueryManager实现,Autofac里更合适的方式是用Keyed注册,直接把DatabaseType枚举作为键,这样后续可以精准匹配:

// 给每个IQueryManager实现绑定对应的DatabaseType键
builder.RegisterType<FirstManager>()
       .Keyed<IQueryManager>(GeneralEnumerations.DatabaseType.First);

builder.RegisterType<SecondManager>()
       .Keyed<IQueryManager>(GeneralEnumerations.DatabaseType.Two);

builder.RegisterType<ThirdManager>()
       .Keyed<IQueryManager>(GeneralEnumerations.DatabaseType.Three);

这种方式比命名注册更贴合你的枚举类型,避免字符串硬编码的问题。

第二步:注册工厂并注入解析逻辑

你之前的写法失效主要有两个原因:一是没给实现做标识,Autofac不知道该解析哪个;二是在注册阶段直接调用Resolve,而Autofac要求容器Build后才能解析。

正确的做法是利用Autofac的IComponentContext上下文,把解析逻辑封装成Func,在工厂实际被使用的时候才去解析,而不是注册阶段。这里有两种简洁的写法:

写法一:直接给工厂注入Func参数

// 先注册一个Func<DatabaseType, IQueryManager>,用上下文来根据键解析
builder.Register<Func<GeneralEnumerations.DatabaseType, IQueryManager>>(ctx =>
{
    var componentContext = ctx.Resolve<IComponentContext>();
    return dbType => componentContext.ResolveKeyed<IQueryManager>(dbType);
});

// 然后正常注册工厂,Autofac会自动把上面的Func注入到工厂的构造函数里
builder.RegisterType<QueryManagerFactory<IQueryManager>>()
       .As<IQueryManagerFactory<IQueryManager>>();

写法二:用ResolvedParameter手动注入

如果你的工厂构造函数需要更精准的参数匹配,可以用这种方式:

builder.RegisterType<QueryManagerFactory<IQueryManager>>()
       .As<IQueryManagerFactory<IQueryManager>>()
       .WithParameter(
           // 匹配构造函数中的Func参数
           new ResolvedParameter(
               (paramInfo, ctx) => paramInfo.ParameterType == typeof(Func<GeneralEnumerations.DatabaseType, IQueryManager>),
               (paramInfo, ctx) => new Func<GeneralEnumerations.DatabaseType, IQueryManager>(dbType => 
                   ctx.ResolveKeyed<IQueryManager>(dbType)
               )
           )
       );

两种方式本质是一样的,都是让Autofac在工厂被实例化时,注入一个能根据DatabaseType获取对应IQueryManager的Func。

第三步:验证使用

当容器Build完成后,你就可以像Unity里那样使用工厂了:

using (var container = builder.Build())
{
    var queryFactory = container.Resolve<IQueryManagerFactory<IQueryManager>>();
    var firstDbManager = queryFactory.GetQueryManager(GeneralEnumerations.DatabaseType.First);
    // 正常使用firstDbManager...
}

为什么你之前的写法不生效?

  1. 缺少实现标识:你没有给每个IQueryManager的实现做命名或键控标记,Autofac无法区分多个实现,默认只会返回最后注册的那个;
  2. 注册阶段Resolve错误:Autofac的ContainerBuilder本身没有Resolve方法,注册时的container参数是IComponentContext,但此时容器还没Build,直接调用Resolve会引发异常或者无法正确解析。

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

火山引擎 最新活动