这些是一些定义:
public interface IClassA
{
}
public class ClassA : IClassA
{
public ClassA()
{
Init();
}
private void Init()
{
Console.WriteLine("Hello!!!");
}
}
public class ClassB
{
private IClassA _classA;
public ClassB(IClassA classA)
{
this._classA = classA;
}
}
如果我构建服务提供者,则在我向 ioc 容器添加更多服务并获取它们后,单例实例将被创建两次或更多次。
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.TryAddSingleton<IClassA,ClassA>();
ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
serviceProvider.GetRequiredService<IClassA>();
serviceCollection.TryAddSingleton<ClassB>();
serviceProvider = serviceCollection.BuildServiceProvider();
serviceProvider.GetRequiredService<ClassB>();
输出为:
Hello!!!
Hello!!!
表示ClassA实例被创建了两次。 我想在第一阶段向 ioc 容器添加一些服务后使用 ServiceProvider。我想在第二阶段向容器中添加一些服务并获取一些服务。 但是,如何确保在第二阶段获得服务后仍会创建单例服务。
由于每个
IServiceProvider
分别跟踪自己的服务,因此使用注册类型的方法将无法正常工作,因为每个提供者最终都会实例化单例,从而导致如您所见的 2 个不同的实例。
如果你真的想要有 2 个提供者(一般来说这是一个坏主意),你可以通过将实例传递给容器来解决这个问题:
var classA = new ClassA();
IServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IClassA>(classA);
ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider();
serviceProvider.GetRequiredService<IClassA>();
serviceCollection.TryAddSingleton<ClassB>();
serviceProvider = serviceCollection.BuildServiceProvider();
serviceProvider.GetRequiredService<ClassB>();
当解析来自任一提供者的任何内容时,它不会尝试实例化该类型,因为您显式提供了实例。
然而,这是一种相当老套的方法,我不会推荐它,除非它确实是你的最后选择。
public static void AddScopedPostBuild<TService>(this ServiceProvider serviceProvider, Func<IServiceProvider, TService> implementationFactory) where TService : class
{
var serviceType = typeof(TService);
var callSiteFactory = serviceProvider.GetPrivatePropertyValue<object>("CallSiteFactory");
var serviceIdentifier = fromServiceTypeMethod.Invoke(null, [ (object)typeof(TService) ]);
var objImplementation = implementationFactory(serviceProvider);
var callSite = constantCallSiteConstructor.Invoke([ typeof(TService), objImplementation ]);
callSiteFactory.CallMethod("Add", serviceIdentifier, callSite);
}