注册不带通用接口和扫描组件的适配器
本文关键字:扫描 组件 适配器 接口 带通 注册 | 更新日期: 2023-09-27 17:59:14
我正在尝试实现以下目标:
- 扫描特定部件(
RegisterAssemblyTypes(assembly)
(。 - 过滤到一个特定的命名空间(
.IsInNamespace("...")
(,它将具有没有公共基本接口的独立接口。 - 将通用适配器注册为通用接口。(
.RegisterGeneric(typeof(Adapter<>)).As(typeof(IAdapter<>))
- 我需要其中的几个注册,每个注册集都将
IAdapter<>
与不同的Adapter<>
实例一起使用。
换句话说,IFoo
和 IBar
可能在命名空间 1 中,IAbc
在命名空间 2 中,我想注册:
-
Adapter<IFoo>
饰IAdapter<IFoo>
-
Adapter<IBar>
饰IAdapter<IBar>
-
Adapter2<IAbc>
或Adapter<IAbc>(customParams)
IAdapter<IAbc>
稍微重复一遍,如果我自己扫描程序集以获取接口,那么我相信我可以做类似的事情(未经测试(:
Type interfaces[] = ...; // Scan assembly and filter to namespace1
foreach (Type interfaceType in interfaces)
{
builder
.Register(context => typeof(Adapter<>).MakeGenericType(interfaceType))
.As(type => typeof(IAdapter<>).MakeGenericType(interfaceType));
}
interfaces = ...; // Interfaces in namespace2
foreach (Type interfaceType in interfaces)
{
builder
.Register(context => typeof(Adapter2<>).MakeGenericType(interfaceType))
.As(type => typeof(IAdapter<>).MakeGenericType(interfaceType));
}
有没有办法使用 Autofac 开箱即用而无需进行自己的扫描/循环? 我已经查看了 Autofac 适配器支持,但这似乎仅适用于通用接口。 RegisterGeneric 也有帮助,但只对一种类型的实例有帮助。
> Autofac 没有内置支持根据泛型参数的类型解析泛型服务。顺便说一下,您可以使用IRegistrationSource
进行动态注册来执行所需的操作。
假设您有这些类型:
namespace A
{
interface IFoo { }
}
namespace B
{
interface IBar { }
}
interface IAdapter<T> { }
class Adapter1<T> : IAdapter<T> { }
class Adapter2<T> : IAdapter<T> { }
class Foo : A.IFoo { }
class Bar : B.IBar { }
你想要这样的东西:
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Foo>().As<A.IFoo>();
builder.RegisterType<Bar>().As<B.IBar>();
builder.RegisterGeneric(typeof(Adapter1<>)).As(typeof(IAdapter<>));
builder.RegisterGeneric(typeof(Adapter2<>)).As(typeof(IAdapter<>));
IContainer container = builder.Build();
var fooAdapter = container.Resolve<IAdapter<A.IFoo>>(); // should return Adapter1<Foo>()
var barAdapter = container.Resolve<IAdapter<B.IBar>>(); // should return Adapter2<Bar>()
当Autofac解析IAdapter<T>
时,它无法找到基于T
命名空间的具体实现。
IRegistrationSource
允许您在 Autofac 需要时动态注册类型。
class TestRegistrationSource : IRegistrationSource
{
public Boolean IsAdapterForIndividualComponents
{
get { return false; }
}
public IEnumerable<IComponentRegistration> RegistrationsFor(
Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
{
IServiceWithType typedService = service as IServiceWithType;
if (typedService == null)
{
yield break;
}
if (!(typedService.ServiceType.IsGenericType
&& typedService.ServiceType.GetGenericTypeDefinition() == typeof(IAdapter<>)))
{
yield break;
}
Type t = typedService.ServiceType.GetGenericArguments()[0];
IComponentRegistration registration =
RegistrationBuilder.ForDelegate((c, p) => c.ResolveNamed(t.Namespace, typedService.ServiceType, p))
.As(service)
.CreateRegistration();
yield return registration;
}
}
当 Autofac 需要时,此IRegistrationSource
将注册一个新的具体实现。当 Autofac 需要IAdapter<A.Foo>
时,它将进入TestRegistrationSource
,该将新IAdapter<A.Foo>
注册为委托,这将解析命名的通用注册IAdapter<T>
为了使TestRegistrationSource
正常工作,您必须更改Adapter1<T>
的注册,Adapter2<T>
使用通用命名注册。
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<Foo>().As<A.IFoo>();
builder.RegisterType<Bar>().As<B.IBar>();
builder.RegisterSource(new TestRegistrationSource());
builder.RegisterGeneric(typeof(Adapter1<>)).Named("Namespace.A", typeof(IAdapter<>));
builder.RegisterGeneric(typeof(Adapter2<>)).Named("Namespace.B", typeof(IAdapter<>));
IContainer container = builder.Build();
var fooAdapter = container.Resolve<IAdapter<A.IFoo>>(); // will return Adapter1<Foo>()
var barAdapter = container.Resolve<IAdapter<B.IBar>>(); // will return Adapter2<Bar>()