繁体   English   中英

在Autofac中使用反射注册多个命名类型

[英]Registering multiple named types using reflection in Autofac

我大约有100个存储库类,它们都实现相同的接口。 它们都有共同的依赖性。

我已经用不同的名称注册了这个通用依赖的两个版本。

我想使用命名的依赖项第二次注册我所有的存储库类。

这基本上是我的原始注册的样子:

builder.RegisterAssemblyTypes(typeof(Repository<>).Assembly)
    .WithParameter(
        new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IClientContext),
            (pi, ctx) => ctx.ResolveNamed<IClientContext>(RegistrationKeys.Published)))
    .AsImplementedInterfaces();

因此,如果我想使用不同的密钥第二次注册所有相同的类型,则需要执行以下操作:

builder.RegisterAssemblyTypes(typeof(Repository<>).Assembly)
    .WithParameter(
        new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IClientContext),
            (pi, ctx) => ctx.ResolveNamed<IClientContext>(RegistrationKeys.Unpublished)))
    .Named(RegistrationKeys.Unpublished)
    .AsImplementedInterfaces();

但是,这将不起作用,因为Named方法要求指定注册的类型,但是它应该基于RegisterAssemblyTypes调用中的一系列解析类型而为动态的。

如何在不向应用程序中添加数百行代码的情况下做到这一点?

您可能可以编写自己的扩展方法来完成此操作。

您可能已经注意到 .Named 的重载 .Named一个函数:

builder.RegisterAssemblyTypes(typeof(AComponent).GetTypeInfo().Assembly)
       .Named(t => t.Name, typeof(object));

该函数接受从程序集中注册的Type ,并使用该Type在服务上生成名称。 不幸的是,该重载也仅将特定的固定类型用作服务类型,因此这会将所有内容注册为Named<object>(...) ,这不是您想要的。

但!

如果您看一下它是如何实现的 ...

public static IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle>
  Named<TLimit, TScanningActivatorData, TRegistrationStyle>(
    this IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle> registration,
    Func<Type, string> serviceNameMapping,
    Type serviceType)
  where TScanningActivatorData : ScanningActivatorData
{
  return registration.As(t => new KeyedService(serviceNameMapping(t), serviceType));
}

...您可以看到基本上是将类型注册,然后将其传递给您提供的函数以生成该名称。 您可以将其更改为采用特定的服务类型,而仅将其注册为自己。

public static IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle>
  NamedSelf<TLimit, TScanningActivatorData, TRegistrationStyle>(
    this IRegistrationBuilder<TLimit, TScanningActivatorData, TRegistrationStyle> registration,
    Func<Type, string> serviceNameMapping)
  where TScanningActivatorData : ScanningActivatorData
{
  return registration.As(t => new KeyedService(serviceNameMapping(t), t));
}

现在使用您的自定义NamedSelf扩展名。

builder.RegisterAssemblyTypes(typeof(Repository<>).Assembly)
    .WithParameter(
        new ResolvedParameter(
            (pi, ctx) => pi.ParameterType == typeof(IClientContext),
            (pi, ctx) => ctx.ResolveNamed<IClientContext>(RegistrationKeys.Unpublished)))
    .NamedSelf(t => RegistrationKeys.Unpublished)
    .AsImplementedInterfaces();

当然,您可以根据需要进行更新。 也许您不希望它成为一个函数,而只是接受一个字符串-很简单。 也许您希望将其注册为命名接口-您可以让函数生成整个KeyedService而不是将其嵌入扩展名中。

要点是,您可以使用现有扩展名作为灵感来编写自己的自定义扩展名,这些自定义扩展名可以满足您的需求,而不必手动注册。

[免责声明:除了我的头脑之外, 没有通过编译器来运行所有这些操作,因此可能会有错别字使复制/粘贴停止编译。 您还需要检查null参数和所有其他内容。 单击链接以查看实际的原始资源。 希望这至少可以解除您的封锁。]

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM