简体   繁体   English

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

[英]Registering multiple named types using reflection in Autofac

I have about 100 repository classes that all implement the same interface. 我大约有100个存储库类,它们都实现相同的接口。 They all have a common dependency. 它们都有共同的依赖性。

I have registered two versions of this common dependency with different names. 我已经用不同的名称注册了这个通用依赖的两个版本。

I want to register all of my repository classes a second time using the named dependency. 我想使用命名的依赖项第二次注册我所有的存储库类。

This is basically what my original registration looks like: 这基本上是我的原始注册的样子:

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

So if I want to register all of the same types a second time, using a different key, I would need to do something like this: 因此,如果我想使用不同的密钥第二次注册所有相同的类型,则需要执行以下操作:

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();

However this won't work, because the Named method requires the type of the registration to be specified, but it should be dynamic based on an array of resolved types from the RegisterAssemblyTypes call. 但是,这将不起作用,因为Named方法要求指定注册的类型,但是它应该基于RegisterAssemblyTypes调用中的一系列解析类型而为动态的。

How can I do this cleanly without having to add hundreds of lines of code to my application? 如何在不向应用程序中添加数百行代码的情况下做到这一点?

You may be able to write your own extension method to accomplish this. 您可能可以编写自己的扩展方法来完成此操作。

You might have noticed that there is an overload of .Named that takes a function: 您可能已经注意到 .Named 的重载 .Named一个函数:

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

That function takes in the Type being registered from the assembly and uses that type to generate the name on the service. 该函数接受从程序集中注册的Type ,并使用该Type在服务上生成名称。 Unfortunately, that overload also only takes a specific fixed type as the service type, so this is registering everything as Named<object>(...) which isn't what you want. 不幸的是,该重载也仅将特定的固定类型用作服务类型,因此这会将所有内容注册为Named<object>(...) ,这不是您想要的。

BUT! 但!

If you look at how that's implemented ... 如果您看一下它是如何实现的 ...

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));
}

...you can see that basically it's taking the type being registered and passing it to a function you provide to generate that name. ...您可以看到基本上是将类型注册,然后将其传递给您提供的函数以生成该名称。 You could change it to not take in a specific service type and just register it as itself. 您可以将其更改为采用特定的服务类型,而仅将其注册为自己。

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));
}

Now use your custom NamedSelf extension. 现在使用您的自定义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();

You can, of course, update that however you want. 当然,您可以根据需要进行更新。 Maybe you don't want it to be a function and just take a string - easy enough. 也许您不希望它成为一个函数,而只是接受一个字符串-很简单。 Maybe you want it to be registered as a named interface - you could have the function generate the whole KeyedService rather than embedding that in the extension. 也许您希望将其注册为命名接口-您可以让函数生成整个KeyedService而不是将其嵌入扩展名中。

Point being, you can use the existing extensions as inspiration for writing your own custom extensions that do what you want and avoid having to manually register things. 要点是,您可以使用现有扩展名作为灵感来编写自己的自定义扩展名,这些自定义扩展名可以满足您的需求,而不必手动注册。

[Disclaimer: I didn't run all this through a compiler other than my mind so there may be a typo that stops a copy/paste from compiling. [免责声明:除了我的头脑之外, 没有通过编译器来运行所有这些操作,因此可能会有错别字使复制/粘贴停止编译。 You'll also want to check for null arguments and all that. 您还需要检查null参数和所有其他内容。 Follow the links to see the actual, original source. 单击链接以查看实际的原始资源。 Hopefully this at least unblocks you.] 希望这至少可以解除您的封锁。]

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

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