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

.NET 8中如何注册工厂类?求替代StructureMap的实现方案

在.NET 8中替代StructureMap的IViewBuilder扫描注册逻辑

我已在.NET 8中实现DefaultViewFactory并完成IViewFactory的注册:

public class DefaultViewFactory : IViewFactory
{
    private readonly IServiceProvider _serviceProvider;

    public DefaultViewFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public TView CreateView<TView>()
    {
        var service = _serviceProvider.GetService<IViewBuilder<TView>>();

        return service != null ? service.Build() : Activator.CreateInstance<TView>();
    }

    public TView CreateView<TInput, TView>(TInput input)
    {
        var service = _serviceProvider.GetService<IViewBuilder<TInput, TView>>();

        if (service != null)
        {
            return service.Build(input);
        }

        return (TView)Activator.CreateInstance(typeof(TView), input)!;
    }
}

注册代码:

serviceCollection.AddTransient<IViewFactory, DefaultViewFactory>();

此前使用StructureMap时,通过以下代码扫描程序集并自动关联IViewBuilder的实现类:

configurationExpression.Scan(assemblyScanner =>
{
    assemblyScanner.TheCallingAssembly();
    assemblyScanner.ConnectImplementationsToTypesClosing(typeof(IViewBuilder<>));
    assemblyScanner.ConnectImplementationsToTypesClosing(typeof(IViewBuilder<,>));
})

IViewBuilder接口定义:

public interface IViewBuilder<out TView>
{
    TView Build();
}

public interface IViewBuilder<in TInput, out TView>
{
    TView Build(TInput input);
}

现在需要在.NET 8原生依赖注入中实现相同的扫描注册逻辑,以下是两种可行方案:


方案1:原生DI手动实现扫描注册

无需依赖第三方库,通过反射手动扫描程序集并完成注册:

var callingAssembly = Assembly.GetCallingAssembly();

// 处理单泛型参数的IViewBuilder<TView>
var singleGenericBuilderType = typeof(IViewBuilder<>);
var singleGenericImplementations = callingAssembly.GetTypes()
    .Where(t => !t.IsAbstract && !t.IsInterface)
    .SelectMany(t => t.GetInterfaces()
        .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == singleGenericBuilderType)
        .Select(i => new { ServiceType = i, ImplementationType = t }));

foreach (var impl in singleGenericImplementations)
{
    serviceCollection.AddTransient(impl.ServiceType, impl.ImplementationType);
}

// 处理双泛型参数的IViewBuilder<TInput, TView>
var doubleGenericBuilderType = typeof(IViewBuilder<,>);
var doubleGenericImplementations = callingAssembly.GetTypes()
    .Where(t => !t.IsAbstract && !t.IsInterface)
    .SelectMany(t => t.GetInterfaces()
        .Where(i => i.IsGenericType && i.GetGenericTypeDefinition() == doubleGenericBuilderType)
        .Select(i => new { ServiceType = i, ImplementationType = t }));

foreach (var impl in doubleGenericImplementations)
{
    serviceCollection.AddTransient(impl.ServiceType, impl.ImplementationType);
}

这段代码会扫描当前调用程序集,筛选出所有非抽象、非接口的IViewBuilder实现类,以瞬态生命周期注册到DI容器,和StructureMap的ConnectImplementationsToTypesClosing逻辑完全一致。


方案2:使用第三方库简化操作

如果觉得手动反射过于繁琐,可以使用Scrutor库,它提供了和StructureMap类似的扫描注册API:

  1. 安装NuGet包:Scrutor
  2. 在Program.cs中添加扫描代码:
serviceCollection.Scan(scan => scan
    .FromCallingAssembly()
    .AddClasses(classes => classes.AssignableToAny(typeof(IViewBuilder<>), typeof(IViewBuilder<,>)))
    .AsImplementedInterfaces()
    .WithTransientLifetime());

这段代码等价于之前StructureMap的逻辑:扫描当前调用程序集,自动将所有实现IViewBuilder<>或IViewBuilder<,>的类注册为对应的接口类型,生命周期为瞬态。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 22:33:12