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

Autofac程序集扫描级ExternallyOwned不生效,如何批量设置?

Autofac批量设置ExternallyOwned问题

定义的类型(AutofacDotMemory程序集)

public interface IOutput : IDisposable
{
    void Write(string content);
}

public class ConsoleOutput : IOutput
{
    public void Write(string content)
    {
        Console.WriteLine(content);
    }

    public void Dispose()
    {
        // TODO release managed resources here
    }
}

public interface IDateWriter : IDisposable
{
    void WriteDate();
}

public class TodayWriter : IDateWriter
{
    private IOutput _output;
    public TodayWriter(IOutput output)
    {
        this._output = output;
    }

    public void WriteDate()
    {
        this._output.Write(DateTime.Today.ToShortDateString());
    }

    public void Dispose()
    {
        // TODO release managed resources here
    }
}

失败的测试代码

尝试通过程序集扫描批量设置ExternallyOwned,但测试失败:

[Test]
public void ExternallyOwnedTest()
{
    var builder = new ContainerBuilder();

    builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly)
           .ExternallyOwned();

    builder.RegisterType<ConsoleOutput>().As<IOutput>();
    builder.RegisterType<TodayWriter>().As<IDateWriter>();

    var container = builder.Build();

    var registration = container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDateWriter)), out var foundRegistration);

    TestContext.WriteLine(registration);

    var isExternallyOwned = registration && foundRegistration.Ownership == InstanceOwnership.ExternallyOwned;

    Assert.IsTrue(isExternallyOwned, $"{nameof(TodayWriter)} is not externally owned");
    container.Dispose();
}

测试失败原因:TodayWriter未被设置为ExternallyOwned。

生效的单个注册代码

针对单个类型添加ExternallyOwned后测试通过:

[Test]
public void ExternallyOwnedTest()
{
    var builder = new ContainerBuilder();
    
    builder.RegisterType<ConsoleOutput>().As<IOutput>();
    builder.RegisterType<TodayWriter>().As<IDateWriter>().ExternallyOwned(); // 此处生效
    
    var container = builder.Build();
    
    var registration = container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDateWriter)), out var foundRegistration);
    
    TestContext.WriteLine(registration);
    
    var isExternallyOwned = registration && foundRegistration.Ownership == InstanceOwnership.ExternallyOwned;
    
    Assert.IsTrue(isExternallyOwned, $"{nameof(TodayWriter)} is not externally owned");
    container.Dispose();
}

疑问

如何确保指定程序集内的所有类型(或通过Where过滤后的多数类型)都被注册为ExternallyOwned,无需逐个添加该配置?


解决方案

问题核心是程序集扫描的注册和后续手动RegisterType注册是独立的,后注册的会覆盖先注册的配置——你先通过程序集扫描给类型加了ExternallyOwned,但之后又手动注册了TodayWriter和ConsoleOutput,覆盖了之前的配置,导致批量设置失效。

要实现批量配置,正确做法是完全通过程序集扫描注册目标类型,避免重复手动注册,以下是几种可行方案:

方案1:全程序集扫描自动匹配接口

扫描目标程序集,过滤出非接口的实现类,自动注册为它们实现的所有接口,并统一设置ExternallyOwned:

[Test]
public void ExternallyOwnedTest()
{
    var builder = new ContainerBuilder();

    // 扫描目标程序集,排除接口,只注册实现类,自动匹配所有实现的接口
    builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly)
           .Where(t => !t.IsInterface && typeof(IDisposable).IsAssignableFrom(t))
           .AsImplementedInterfaces()
           .ExternallyOwned();

    var container = builder.Build();

    var registration = container.ComponentRegistry.TryGetRegistration(new TypedService(typeof(IDateWriter)), out var foundRegistration);

    TestContext.WriteLine(registration);

    var isExternallyOwned = registration && foundRegistration.Ownership == InstanceOwnership.ExternallyOwned;

    Assert.IsTrue(isExternallyOwned, $"{nameof(TodayWriter)} is not externally owned");
    container.Dispose();
}

方案2:扫描时过滤特定类型

如果只需要给程序集中的部分类型批量设置,可以通过Where精准筛选:

builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly)
       .Where(t => t == typeof(TodayWriter) || t == typeof(ConsoleOutput))
       .AsImplementedInterfaces()
       .ExternallyOwned();

方案3:自定义模块统一配置

对于复杂场景,可创建Autofac模块封装批量注册逻辑,方便复用:

public class ExternallyOwnedModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        // 在这里定义批量注册规则
        builder.RegisterAssemblyTypes(typeof(IDateWriter).Assembly)
               .Where(t => typeof(IDateWriter).IsAssignableFrom(t) || typeof(IOutput).IsAssignableFrom(t))
               .AsImplementedInterfaces()
               .ExternallyOwned();
    }
}

// 测试中使用模块
[Test]
public void ExternallyOwnedTest()
{
    var builder = new ContainerBuilder();
    builder.RegisterModule<ExternallyOwnedModule>();

    var container = builder.Build();
    // 后续测试逻辑不变
}

只要避免对同一类型重复注册,批量设置ExternallyOwned就能生效。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 00:35:03