检视这三者类型的构造方法,可以很容易理解Scoped与Singleton是通过缓存的方式实现对象的重用。
public TransientCallSite(IServiceCallSite serviceCallSite) { ServiceCallSite = serviceCallSite; } public ScopedCallSite(IServiceCallSite serviceCallSite, object cacheKey) { ServiceCallSite = serviceCallSite; CacheKey = cacheKey; } public SingletonCallSite(IServiceCallSite serviceCallSite, object cacheKey) : base(serviceCallSite, cacheKey) { } 性能由于ServiceProvider容器使用了反射,表达式树以及IL Emit方式创建对象,可能会对其性能有所担忧,但实际检测的结果,除了Runtime引擎表现不尽如人意外,其它引擎的性能还是在可接受范围内的。
public class GetServiceBenchmark { private const int OperationsPerInvoke = 50000; private IServiceProvider _transientSp; private ServiceProviderMode _mode; [Params("Expressions", "Dynamic", "Runtime", "ILEmit")] public string Mode { set { _mode = (ServiceProviderMode)Enum.Parse(typeof(ServiceProviderMode), value); } } [Benchmark(Baseline = true, OperationsPerInvoke = OperationsPerInvoke)] public void NoDI() { for (int i = 0; i < OperationsPerInvoke; i++) { var temp = new A(new B(new C())); temp.Foo(); } } [GlobalSetup(Target = nameof(Transient))] public void SetupTransient() { var services = new ServiceCollection(); services.AddTransient<A>(); services.AddTransient<B>(); services.AddTransient<C>(); _transientSp = services.BuildServiceProvider(new ServiceProviderOptions() { Mode = _mode }); } [Benchmark(OperationsPerInvoke = OperationsPerInvoke)] public void Transient() { for (int i = 0; i < OperationsPerInvoke; i++) { var temp = _transientSp.GetService<A>(); temp.Foo(); } } private class A { public A(B b) { } [MethodImpl(MethodImplOptions.NoInlining)] public void Foo() { } } private class B { public B(C c) { } } private class C { } } // ***** BenchmarkRunner: Finish ***** // * Export * // * Detailed results * GetServiceBenchmark.NoDI: Job-NHLENA(Toolchain=InProcessToolchain, RunStrategy=Throughput) [Mode=Dynamic] Runtime = ; GC = Mean = 5.5175 ns, StdErr = 0.0116 ns (0.21%); N = 15, StdDev = 0.0449 ns Min = 5.4490 ns, Q1 = 5.4860 ns, Median = 5.5207 ns, Q3 = 5.5641 ns, Max = 5.5972 ns IQR = 0.0781 ns, LowerFence = 5.3688 ns, UpperFence = 5.6813 ns ConfidenceInterval = [5.4695 ns; 5.5654 ns] (CI 99.9%), Margin = 0.0480 ns (0.87% of Mean) Skewness = 0.15, Kurtosis = 1.67 GetServiceBenchmark.Transient: Job-NHLENA(Toolchain=InProcessToolchain, RunStrategy=Throughput) [Mode=Dynamic] Runtime = ; GC = Mean = 43.1601 ns, StdErr = 0.0677 ns (0.16%); N = 15, StdDev = 0.2620 ns Min = 42.7731 ns, Q1 = 42.9117 ns, Median = 43.2403 ns, Q3 = 43.3580 ns, Max = 43.5392 ns IQR = 0.4464 ns, LowerFence = 42.2421 ns, UpperFence = 44.0276 ns ConfidenceInterval = [42.8800 ns; 43.4402 ns] (CI 99.9%), Margin = 0.2801 ns (0.65% of Mean) Skewness = -0.2, Kurtosis = 1.59 GetServiceBenchmark.NoDI: Job-NHLENA(Toolchain=InProcessToolchain, RunStrategy=Throughput) [Mode=Expressions] Runtime = ; GC = Mean = 5.6964 ns, StdErr = 0.0388 ns (0.68%); N = 33, StdDev = 0.2226 ns Min = 5.5148 ns, Q1 = 5.5603 ns, Median = 5.6042 ns, Q3 = 5.6769 ns, Max = 6.2460 ns IQR = 0.1166 ns, LowerFence = 5.3854 ns, UpperFence = 5.8518 ns ConfidenceInterval = [5.5561 ns; 5.8368 ns] (CI 99.9%), Margin = 0.1404 ns (2.46% of Mean) Skewness = 1.48, Kurtosis = 3.69 GetServiceBenchmark.Transient: Job-NHLENA(Toolchain=InProcessToolchain, RunStrategy=Throughput) [Mode=Expressions] Runtime = ; GC = Mean = 43.6662 ns, StdErr = 0.0995 ns (0.23%); N = 13, StdDev = 0.3586 ns Min = 43.1083 ns, Q1 = 43.5089 ns, Median = 43.6051 ns, Q3 = 43.7178 ns, Max = 44.6669 ns IQR = 0.2089 ns, LowerFence = 43.1956 ns, UpperFence = 44.0311 ns ConfidenceInterval = [43.2368 ns; 44.0957 ns] (CI 99.9%), Margin = 0.4295 ns (0.98% of Mean) Skewness = 1.41, Kurtosis = 5.18 GetServiceBenchmark.NoDI: Job-NHLENA(Toolchain=InProcessToolchain, RunStrategy=Throughput) [Mode=ILEmit] Runtime = ; GC = Mean = 5.6016 ns, StdErr = 0.0071 ns (0.13%); N = 13, StdDev = 0.0255 ns Min = 5.5547 ns, Q1 = 5.5896 ns, Median = 5.5996 ns, Q3 = 5.6226 ns, Max = 5.6400 ns IQR = 0.0330 ns, LowerFence = 5.5401 ns, UpperFence = 5.6721 ns ConfidenceInterval = [5.5712 ns; 5.6321 ns] (CI 99.9%), Margin = 0.0305 ns (0.54% of Mean) Skewness = -0.47, Kurtosis = 2.12 GetServiceBenchmark.Transient: Job-NHLENA(Toolchain=InProcessToolchain, RunStrategy=Throughput) [Mode=ILEmit] Runtime = ; GC = Mean = 43.1397 ns, StdErr = 0.0726 ns (0.17%); N = 15, StdDev = 0.2812 ns Min = 42.7061 ns, Q1 = 42.9064 ns, Median = 43.1052 ns, Q3 = 43.3093 ns, Max = 43.6443 ns IQR = 0.4028 ns, LowerFence = 42.3022 ns, UpperFence = 43.9135 ns ConfidenceInterval = [42.8392 ns; 43.4403 ns] (CI 99.9%), Margin = 0.3006 ns (0.70% of Mean) Skewness = 0.28, Kurtosis = 1.9 GetServiceBenchmark.NoDI: Job-NHLENA(Toolchain=InProcessToolchain, RunStrategy=Throughput) [Mode=Runtime] Runtime = ; GC = Mean = 6.4814 ns, StdErr = 0.0762 ns (1.18%); N = 100, StdDev = 0.7617 ns Min = 5.4979 ns, Q1 = 5.8327 ns, Median = 6.3039 ns, Q3 = 6.9775 ns, Max = 8.0420 ns IQR = 1.1448 ns, LowerFence = 4.1155 ns, UpperFence = 8.6947 ns ConfidenceInterval = [6.2231 ns; 6.7397 ns] (CI 99.9%), Margin = 0.2583 ns (3.99% of Mean) Skewness = 0.52, Kurtosis = 1.94 GetServiceBenchmark.Transient: Job-NHLENA(Toolchain=InProcessToolchain, RunStrategy=Throughput) [Mode=Runtime] Runtime = ; GC = Mean = 581.5066 ns, StdErr = 1.6962 ns (0.29%); N = 15, StdDev = 6.5695 ns Min = 571.4934 ns, Q1 = 576.3829 ns, Median = 580.8121 ns, Q3 = 587.2645 ns, Max = 596.3317 ns IQR = 10.8816 ns, LowerFence = 560.0605 ns, UpperFence = 603.5869 ns ConfidenceInterval = [574.4834 ns; 588.5297 ns] (CI 99.9%), Margin = 7.0232 ns (1.21% of Mean) Skewness = 0.58, Kurtosis = 2.48 Total time: 00:03:11 (191.85 sec) 第三方容器如果想用第三方容器替换ASP.NET Core原有的容器也是可以办到的。以最常见的Autofac为例,有两种实现方式: