依赖注入学习总结2

服务的生命周期

1.AddTransient类型的声明周期对象

声明一个测试的接口和测试用到的类:

    public interface ITestService
    {
        public string Name { get; set; }
        public void SayHi();
    }


    public class TestServiceImpl1 : ITestService
    {
        public string Name { get; set; }

        public void SayHi()
        {
            Console.WriteLine($"hello,I'm {Name}");
        }
    }
static void Main(string[] args)
        {
            //生命周期
            {
                ServiceCollection services = new ServiceCollection(); //用来构建容器对象
                services.AddTransient<TestServiceImpl1>();
                using (ServiceProvider sp = services.BuildServiceProvider()) //ServiceProvider 服务定位器
                {
                    TestServiceImpl1 t = sp.GetService<TestServiceImpl1>();
                    t.Name = "jam";
                    t.SayHi();//jam

                    TestServiceImpl1 t1 = sp.GetService<TestServiceImpl1>();
                    t1.Name = "tom";
                    t1.SayHi();//tom

                    t.SayHi();//jam

                    Console.WriteLine(object.ReferenceEquals(t, t1));//false
                }
            }


            Console.Read();
        }

执行结果:

AddTransient类型的声明周期对象,每次调用都会生成一个新的对象。

2.AddSingleton类型的声明周期对象

static void Main(string[] args)
        {
            //生命周期 AddSingleton
            {
                ServiceCollection services = new ServiceCollection(); //用来构建容器对象
                services.AddSingleton<TestServiceImpl1>();
                using (ServiceProvider sp = services.BuildServiceProvider()) //ServiceProvider 服务定位器
                {
                    TestServiceImpl1 t = sp.GetService<TestServiceImpl1>();
                    t.Name = "jam";
                    t.SayHi();//jam

                    TestServiceImpl1 t1 = sp.GetService<TestServiceImpl1>();
                    t1.Name = "tom";
                    t1.SayHi();//tom

                    t.SayHi();//tom

                    Console.WriteLine(object.ReferenceEquals(t, t1));//true
                }
            }


            Console.Read();
        }

执行结果:

AddSingleton类型的声明周期对象,每次调用都是同一个对象。

3.AddScoped类型的声明周期对象

static void Main(string[] args)
        {
            //生命周期 AddScoped
            {
                ServiceCollection services = new ServiceCollection(); //用来构建容器对象
                services.AddScoped<TestServiceImpl1>();
                using (ServiceProvider sp = services.BuildServiceProvider()) //ServiceProvider 服务定位器
                {
                    using (IServiceScope scope = sp.CreateScope())
                    {
                        //在scope中获取scope相关的对象,而不是sp
                        TestServiceImpl1 t = scope.ServiceProvider.GetService<TestServiceImpl1>();
                        t.Name = "jam";
                        t.SayHi();//jam

                        TestServiceImpl1 t1 = scope.ServiceProvider.GetService<TestServiceImpl1>();
                        t1.Name = "tom";
                        t1.SayHi();//tom

                        t.SayHi();//tom

                        Console.WriteLine(object.ReferenceEquals(t, t1));//true
                    }
                }
            }


            Console.Read();
        }

执行结果:

static void Main(string[] args)
        {
            //生命周期 AddScoped
            {
                ServiceCollection services = new ServiceCollection(); //用来构建容器对象
                services.AddScoped<TestServiceImpl1>();
                using (ServiceProvider sp = services.BuildServiceProvider()) //ServiceProvider 服务定位器
                {
                    TestServiceImpl1 test;

                    using (IServiceScope scope = sp.CreateScope())
                    {
                        //在scope中获取scope相关的对象,而不是sp
                        TestServiceImpl1 t = scope.ServiceProvider.GetService<TestServiceImpl1>();
                        t.Name = "jam";
                        t.SayHi();//jam

                        TestServiceImpl1 t1 = scope.ServiceProvider.GetService<TestServiceImpl1>();
                        t1.Name = "tom";
                        t1.SayHi();//tom

                        t.SayHi();//tom

                        Console.WriteLine(object.ReferenceEquals(t, t1));//true

                        test = t1;
                    }

                    Console.WriteLine("____________________________________");

                    using (IServiceScope scope2 = sp.CreateScope())
                    {
                        //在scope中获取scope相关的对象,而不是sp
                        TestServiceImpl1 t = scope2.ServiceProvider.GetService<TestServiceImpl1>();
                        t.Name = "jam";
                        t.SayHi();//jam

                        TestServiceImpl1 t1 = scope2.ServiceProvider.GetService<TestServiceImpl1>();
                        t1.Name = "tom";
                        t1.SayHi();//tom

                        t.SayHi();//tom

                        Console.WriteLine(object.ReferenceEquals(t, t1));//true

                        //两个不同using范围的对象进行比较
                        Console.WriteLine(object.ReferenceEquals(test, t1));//false
                    }

                }
            }


            Console.Read();
        }

执行结果:

AddScoped类型的声明周期对象,如果对象在同一个using范围中,每次调用都是同一个对象。

如果在不同的using范围中,调用的则是不同的对象。

总结:

1.使用ServiceProvider.CreateScope()创建scope

2.如果一个类实现了IDisposable接口,则离开作用域后,容器会自动调用对象的Dispose()方法

3.不要在长生命周期对象中引用比它短的生命周期对象。在asp.net core中,这样做默认会抛异常

4.声明周期的选择:如果类无状态,建议用Singleton;如果类有状态,且有Scope,建议用Scoped,因为通常这种Scope控制下的代码都是运行在同一个线程中的,没有并发修改的问题;在使用Transient的时候要谨慎

猜你喜欢

转载自blog.csdn.net/liangmengbk/article/details/121321578