.net IServiceProvider不返回Singleton示例

0md85ypi  于 2023-04-22  发布在  .NET
关注(0)|答案(2)|浏览(119)

我正在使用.Net Core,我目前面临的是它的DI引擎。
我的项目是一个类库,因此,asp的绑定在这里无关紧要。
我遵循了this article的提示,以便使DI工作。

现在,到多汁的部分:

我创建了一个服务提供程序,它看起来像这样:

public static class ServiceProvider
    {
        public static IServiceProvider GetServiceProvider()
        {
            var services = new ServiceCollection();

            //Singletons
            services.AddSingleton<IInstance, Instance>();

            //Transients
            services.AddTransient<IDate, Date>();
            services.AddTransient<IMath, Math>();
            services.AddTransient<INumber, Number>();
            return services.BuildServiceProvider();
        }
    }

然后我尝试在一个静态类中执行它,看起来像这样:

public static class MySingleton
    {
        public static IInstance Instance
            => ServiceProvider.GetServiceProvider().GetService<IInstance>();
    }

为了测试单例行为,我这样测试了它:

[Test]
        public void Instance_HundredTimes_ReturnsSameInstance()
        {
            //Arrange
            const int callCount = 100;
            var results = new IInstance[callCount];

            //Act
            for (var i = 0; i < callCount; i++)
            {
                results[i] = MySingleton.Instance;
            }

            //Assert
            Assert.That(results.Distinct().Count(), Is.EqualTo(1));
        }

测试结果是否定的,而不是在distinct之后有一个引用(因为它是一个单例),我仍然有一百个示例。
我做错什么了吗
我在配置中遗漏了什么吗?

fzwojiic

fzwojiic1#

你的问题在这个代码块中:

public static class MySingleton
{
    public static IInstance Instance
        => ServiceProvider.GetServiceProvider().GetService<IInstance>();
}

这里的做法是在每次访问属性时调用ServiceProvider.GetServiceProvider().GetService<IInstance>()。这意味着实际上并没有 * 拥有 * 一个单例。你要做的是设置一次单例示例:

public static class MySingleton
{
    public static IInstance Instance
    {
        get;
    } = ServiceProvider.GetServiceProvider().GetService<IInstance>();
}

此外,在创建服务时也会遇到类似的问题。每次调用GetServiceProvider()时都会创建一个新的ServiceCollection。您可能不希望这样。您可能希望这样做:

public static class ServiceProvider
{
    private static IServiceProvider serviceProvider = null;

    public static IServiceProvider GetServiceProvider()
    {
        if (serviceProvider == null) 
        {
            var services = new ServiceCollection();

            //Singletons
            services.AddSingleton<IInstance, Instance>();

            //Transients
            services.AddTransient<IDate, Date>();
            services.AddTransient<IMath, Math>();
            services.AddTransient<INumber, Number>();

            serviceProvider = services.BuildServiceProvider();
        }
        return serviceProvider;
    }
}
raogr8fs

raogr8fs2#

问题:

我的问题在于没有在MySingleton中保留我的IserviceProvider示例

解决方案:

TL;DR

有一个IserviceProvider的静态示例

代码重构

重构ServiceProvider如下:

public class LodashServiceProvider
{
    private static readonly Lazy<IServiceProvider> LazyServiceProvider;

    static LodashServiceProvider()
    {
        LazyServiceProvider = new Lazy<IServiceProvider>(InitializeServiceProvider);
    }

    public static IServiceProvider GetServiceProvider() => LazyServiceProvider.Value;

    private static IServiceProvider InitializeServiceProvider()
    {
        var services = new ServiceCollection();

        //Singletons
        services.AddSingleton<ILodashInstance, LodashInstance>();

        //Transients
        services.AddTransient<ILodashDate, LodashDate>();
        services.AddTransient<ILodashMath, LodashMath>();
        services.AddTransient<ILodashNumber, LodashNumber>();
        return services.BuildServiceProvider();
    }
}

我想感谢KiziuSefe对这个问题的解决方案。

相关问题