.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:
- 安装NuGet包:
Scrutor - 在Program.cs中添加扫描代码:
serviceCollection.Scan(scan => scan .FromCallingAssembly() .AddClasses(classes => classes.AssignableToAny(typeof(IViewBuilder<>), typeof(IViewBuilder<,>))) .AsImplementedInterfaces() .WithTransientLifetime());
这段代码等价于之前StructureMap的逻辑:扫描当前调用程序集,自动将所有实现IViewBuilder<>或IViewBuilder<,>的类注册为对应的接口类型,生命周期为瞬态。
内容的提问来源于stack exchange,提问作者iggyweb
相关产品推荐
相关产品推荐

