簡體   English   中英

注冊使用開放泛型類型將多個接口實現為單例的服務

[英]Registering service that implements several interfaces as singleton using open generic type

有一個通用MyClass<T>實現了 2 個通用接口IMyInterface1<T>IMyInterface2<T> 我想將其注冊為單身人士。 因此,對於給定的T兩個接口都將解析為MyClass的同一實例。

我正在嘗試將其注冊為開放泛型類型並轉發到工廠方法:

services.AddSingleton(typeof(MyClass<>));
services.AddSingleton(typeof(IMyInterface1<>), sp => sp.GetRequiredService(typeof(MyClass<>)));
services.AddSingleton(typeof(IMyInterface2<>), sp => sp.GetRequiredService(typeof(MyClass<>)));

但是在運行時我收到異常消息“打開通用服務類型‘IMyInterface1`1[T]’需要注冊一個開放的通用實現類型。

當我為每個具體類型T注冊我的單例時,即沒有開放泛型類型,一切正常:

services.AddSingleton(typeof(MyClass<A>));
services.AddSingleton(typeof(IMyInterface1<A>), sp => sp.GetRequiredService(typeof(MyClass<A>)));
services.AddSingleton(typeof(IMyInterface2<A>), sp => sp.GetRequiredService(typeof(MyClass<A>)));
services.AddSingleton(typeof(MyClass<B>));
services.AddSingleton(typeof(IMyInterface1<B>), sp => sp.GetRequiredService(typeof(MyClass<B>)));
services.AddSingleton(typeof(IMyInterface2<B>), sp => sp.GetRequiredService(typeof(MyClass<B>)));

我知道還有另一種方法來注冊具有兩個接口的單例服務 - 通過提供實現實例而不是實現工廠。 但是我不能在“現實世界”中使用它,因為我的真實類也有很多依賴項,並且在注冊階段可能無法解決所有這些依賴項。

有沒有辦法使用開放的泛型類型來解決這個問題?


詳細異常:

System.ArgumentException
  HResult=0x80070057
  Message=Open generic service type 'IMyInterface1`1[T]' requires registering an open generic implementation type. (Parameter 'descriptors')
  Source=Microsoft.Extensions.DependencyInjection
  StackTrace:
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.Populate()
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory..ctor(IEnumerable`1 descriptors)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine..ctor(IEnumerable`1 serviceDescriptors, IServiceProviderEngineCallback callback)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CompiledServiceProviderEngine..ctor(IEnumerable`1 serviceDescriptors, IServiceProviderEngineCallback callback)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider..ctor(IEnumerable`1 serviceDescriptors, ServiceProviderOptions options)
   at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services, ServiceProviderOptions options)
   at Microsoft.Extensions.DependencyInjection.ServiceCollectionContainerBuilderExtensions.BuildServiceProvider(IServiceCollection services)
   at WebApplication1.Startup.ConfigureServices(IServiceCollection services) in ...\WebApplication1\WebApplication1\Startup.cs:line 39
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.InvokeCore(Object instance, IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass9_0.<Invoke>g__Startup|0(IServiceCollection serviceCollection)
   at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.Invoke(Object instance, IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.ConfigureServicesBuilder.<>c__DisplayClass8_0.<Build>b__0(IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.UseStartup(Type startupType, HostBuilderContext context, IServiceCollection services)
   at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass12_0.<UseStartup>b__0(HostBuilderContext context, IServiceCollection services)
   at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at WebApplication1.Program.Main(String[] args) in ...\WebApplication1\WebApplication1\Program.cs:line 16

看起來你不能這樣做 - 它不受支持。

以下問題似乎已經要求這樣做:

如果您將接口注冊上的sp => sp.GetRequiredService(typeof(MyClass<A>))替換為typeof(MyClass<A>)那么您將最終為您注冊的每個接口獲得一個單例實例,它不會聽起來不像你想要的。

我能想到的最好的方法是將MyClass<T>變成管理其自己的底層實現的單例實例的外觀。 您可以通過將 Facade 調用到帶有靜態字典的非泛型類(靜態成員是每個泛型類型,因此這需要是非泛型類)來實現每個T檢索真正的單例實例。

例子

注冊您的服務:

services.AddSingleton(typeof(MyFacadeClass<>));
services.AddSingleton(typeof(IMyInterface1<>), typeof(MyFacadeClass<>));
services.AddSingleton(typeof(IMyInterface2<>), typeof(MyFacadeClass<>));

外觀實現:

public class MyImplementationClass<T> : IMyInterface1<T>, IMyInterface2<T>
{
    public void Interface1Method()
    {
    }

    public void Interface2Method()
    {
    }
}

public class MyClassSingletonRegister
{
    public static Dictionary<Type, object> MyImplementationClassInstances = new Dictionary<Type, object>();
}

public class MyFacadeClass<T> : IMyInterface1<T>, IMyInterface2<T>
{
    private readonly MyImplementationClass<T> _instance;

    public MyFacadeClass()
    {
        _instance = GetInstance();
    }

    private MyImplementationClass<T> GetInstance()
    {
        if (!MyClassSingletonRegister.MyImplementationClassInstances.TryGetValue(typeof(T), out var instance))
        {
            Debug.WriteLine("Creating new instance for " + typeof(T).Name);
            var myImplementationClass = new MyImplementationClass<T>();
            MyClassSingletonRegister.MyImplementationClassInstances.Add(typeof(T), myImplementationClass);

            instance = myImplementationClass;
        }

        return (MyImplementationClass<T>) instance;
    }


    public void Interface1Method()
    {
        _instance.Interface1Method();
    }

    public void Interface2Method()
    {
        _instance.Interface2Method();
    }
}

public interface IMyInterface1<T>
{
    void Interface1Method();
}

public interface IMyInterface2<T>
{
    void Interface2Method();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM