もくじ
https://tera1707.com/entry/2022/02/06/144447
やりたいこと
以前の記事で、DIするときの勉強をして、ごちゃごちゃいろいろ書いたので、ササっとコピペして使えるように部品どりコードを置いておきたい。
前提
- Windows10 Home 21H1 19043.1706
- VisualStudio2022 Community 17.1.4
- WinUI3.0
- Windows App SDK 1.0
- NUnitで単体テスト実施
- 2022年6月の時点の調査
コード
AddTransientの場合(取るたびに異なるインスタンスが取れるパターン)
///////////////////////// 登録部分(プログラムの最初で行う) ///////////////////////// var services = new ServiceCollection(); services.AddTransient<IGetCurrentTimeModel, GetCurrentTimeModel>(); // ① services.AddTransient<IGetCurrentTimeModel>((a) => new GetCurrentTimeModel(99)); // ② var provider = services.BuildServiceProvider(); Ioc.Default.ConfigureServices(provider); ///////////////////////// 使う部分(登録したインスタンスを使う個所で行う) ///////////////////////// var a1 = Ioc.Default.GetRequiredService<IGetCurrentTimeModel>(); // ②が取れるのは同じだが、 var a2 = Ioc.Default.GetRequiredService<IGetCurrentTimeModel>(); // 別インスタンスが取れる Debug.WriteLine(a1 == a2); // →false(別インスタンスが取れた)
AddSingletonの場合(取るたびに同じインスタンスが取れるパターン)
///////////////////////// 登録部分(プログラムの最初で行う) ///////////////////////// // ServiceCollectionを作成 var services = new ServiceCollection(); // インスタンスを登録 services.AddSingleton<IGetCurrentTimeModel, GetCurrentTimeModel>(); // ① services.AddSingleton<IGetCurrentTimeModel>((a) => new GetCurrentTimeModel(99)); // ② // サービスプロバイダ、サービスを作成 var provider = services.BuildServiceProvider(); Ioc.Default.ConfigureServices(provider); ///////////////////////// 使う部分(登録したインスタンスを使う個所で行う) ///////////////////////// // 登録したインスタンスを使う var a1 = Ioc.Default.GetRequiredService<IGetCurrentTimeModel>(); // 同じクラスを重複して登録した場合は、 var a2 = Ioc.Default.GetRequiredService<IGetCurrentTimeModel>(); // どちらも、②(引数アリのほう)の同じインスタンスが取れる Debug.WriteLine(a1==a2); // →true(同じインスタンスが取れた)
AddScopedの場合(指定したスコープ内では同じインスタンス、異なるスコープでは異なるインスタンスが取れるパターン)
///////////////////////////////// var services = new ServiceCollection(); services.AddScoped<IGetCurrentTimeModel>((a) => new GetCurrentTimeModel(99)); // ② services.AddScoped<IGetCurrentTimeModel, GetCurrentTimeModel>(); // ① var provider = services.BuildServiceProvider(); provider.CreateScope(); Ioc.Default.ConfigureServices(provider); ///////////////////////////////// IGetCurrentTimeModel gctm1; IGetCurrentTimeModel gctm2; IGetCurrentTimeModel gctm3; IGetCurrentTimeModel gctm4; using (var scope1 = Ioc.Default.CreateScope()) { gctm1 = scope1.ServiceProvider.GetService<IGetCurrentTimeModel>(); gctm2 = scope1.ServiceProvider.GetService<IGetCurrentTimeModel>(); } using (var scope2 = Ioc.Default.CreateScope()) { gctm3 = scope2.ServiceProvider.GetService<IGetCurrentTimeModel>(); gctm4 = scope2.ServiceProvider.GetService<IGetCurrentTimeModel>(); } Debug.WriteLine(gctm1 == gctm2);// スコープが同じなので、1と2は同じ、3と4も同じインスタンス。 Debug.WriteLine(gctm1 == gctm3);// スコープが異なるので、1と3は異なるインスタンス。
AddSingletonとAddTransientで同じinterfaceを登録した場合のメモ)
後勝ちになるっぽい。
///////////////////////////////// var services = new ServiceCollection(); services.AddSingleton<IGetCurrentTimeModel, GetCurrentTimeModel>(); // ① services.AddTransient<IGetCurrentTimeModel>((a) => new GetCurrentTimeModel(99)); // ② var provider = services.BuildServiceProvider(); Ioc.Default.ConfigureServices(provider); ///////////////////////////////// var a1 = Ioc.Default.GetRequiredService<IGetCurrentTimeModel>(); // 後で登録したほうの方式(SingletonかTransientか)で、 var a2 = Ioc.Default.GetRequiredService<IGetCurrentTimeModel>(); // 取れる Debug.WriteLine(a1 == a2); // →Transientが後なのでfalse(Singletonならtrueになる)
参考
以前のDIについての記事