[英]Registering service that implements several interfaces as singleton using open generic type
There is a generic MyClass<T>
that implements 2 generic interfaces IMyInterface1<T>
and IMyInterface2<T>
.有一个通用
MyClass<T>
实现了 2 个通用接口IMyInterface1<T>
和IMyInterface2<T>
。 I want to register it as a singleton.我想将其注册为单身人士。 So for a given
T
both interfaces will be resolved to the same instance of MyClass
.因此,对于给定的
T
两个接口都将解析为MyClass
的同一实例。
I'm trying to register it as open generic type with forwarding to a factory method:我正在尝试将其注册为开放泛型类型并转发到工厂方法:
services.AddSingleton(typeof(MyClass<>));
services.AddSingleton(typeof(IMyInterface1<>), sp => sp.GetRequiredService(typeof(MyClass<>)));
services.AddSingleton(typeof(IMyInterface2<>), sp => sp.GetRequiredService(typeof(MyClass<>)));
but then in runtime I'm getting exception with message " Open generic service type 'IMyInterface1`1[T]' requires registering an open generic implementation type. "但是在运行时我收到异常消息“打开通用服务类型‘IMyInterface1`1[T]’需要注册一个开放的通用实现类型。 ”
When I'm registering my singleton for every concrete type T
, ie without open generic type, all works fine:当我为每个具体类型
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>)));
I know that there is another way to register a singleton service with two interfaces - by providing implementation instance instead of implementation factory.我知道还有另一种方法来注册具有两个接口的单例服务 - 通过提供实现实例而不是实现工厂。 But I can't use this in "real world" because my real class also has a lot of dependencies and it is probably impossible to resolve all of them at registration stage.
但是我不能在“现实世界”中使用它,因为我的真实类也有很多依赖项,并且在注册阶段可能无法解决所有这些依赖项。
Is there a way to solve this issue using open generic types?有没有办法使用开放的泛型类型来解决这个问题?
Detailed exception:详细异常:
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
It looks like you can't do this - it's not supported.看起来你不能这样做 - 它不受支持。
The following issues look to have already requested this:以下问题似乎已经要求这样做:
If you replace sp => sp.GetRequiredService(typeof(MyClass<A>))
on the interface registrations with typeof(MyClass<A>)
then you will end up with a singleton instance for each interface you've registered, which doesn't sound like what you want.如果您将接口注册上的
sp => sp.GetRequiredService(typeof(MyClass<A>))
替换为typeof(MyClass<A>)
那么您将最终为您注册的每个接口获得一个单例实例,它不会听起来不像你想要的。
The best I can think of, and it's not particularly pretty, is that you turn MyClass<T>
into a facade that manages its own singleton instance of the underlying implementation.我能想到的最好的方法是将
MyClass<T>
变成管理其自己的底层实现的单例实例的外观。 You could do this by having the facade call into a non-generic class with a static dictionary (static members are per-generic type so this needs to be a non-generic class) to retrieve a truly singleton instance per T
.您可以通过将 Facade 调用到带有静态字典的非泛型类(静态成员是每个泛型类型,因此这需要是非泛型类)来实现每个
T
检索真正的单例实例。
Example例子
Register your services:注册您的服务:
services.AddSingleton(typeof(MyFacadeClass<>));
services.AddSingleton(typeof(IMyInterface1<>), typeof(MyFacadeClass<>));
services.AddSingleton(typeof(IMyInterface2<>), typeof(MyFacadeClass<>));
Facade implementation:外观实现:
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.