簡體   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