Xamarin.FormsのDependencyService.Get<T>()はSingletonなのか?
DependencyServiceとは
DependencyServiceはXamarin 3.0で追加されたXamarin.Formsに含まれる、依存性注入のための仕組みです。ドキュメントはこちら。
Accessing Native Features via the DependencyService
DependencyServiceの使い方
ドキュメントを要約すると以下のような感じです。
- Sharedプロジェクトでインターフェースを定義。
- 各プラットフォームのプロジェクトでインターフェースを実装。
- assemblyに付けるDependencyという属性でインターフェースの実装クラスを宣言。
DependencyService.Get<T>()
でインスタンスを取ってきて使う。
結論:DependencyService.Get<T>()のパラメータで変わる
DependencyService.Get<T>()
の引数にDependencyFetchTarget.GlobalInstance
を指定すると常に同じインスタンスを取得できます。これはデフォルト引数でもあるため、何も指定しない場合も同じ結果になります。
新しいインスタンスを取得したい場合は、引数にDependencyFetchTarget.NewInstance
を指定します。
検証
新規にUniversal Xamarin.Forms Project(PCL)を作成します。
Sharedプロジェクトにインターフェースを定義。
namespace FormsDI { public interface ICounter { int GetCurrent(); int CountUp(); } }
実装クラスAndroid側。
using Xamarin.Forms; using FormsDI; using FormsDI.Android; [assembly : Dependency(typeof(Counter_Android))] namespace FormsDI.Android { public class Counter_Android : ICounter { private int count = 0; public Counter_Android () { } public int GetCurrent() { return count; } public int CountUp() { return ++count; } } }
実装クラスiOS側。
using Xamarin.Forms; using FormsDI; using FormsDI.iOS; [assembly : Dependency(typeof(Counter_iOS))] namespace FormsDI.iOS { public class Counter_iOS : ICounter { private int count = 0; public Counter_iOS () { } public int GetCurrent() { return count; } public int CountUp() { return ++count; } } }
Sharedプロジェクトにメインページ定義とDependencyService取得のコードを追加します。
using Xamarin.Forms; namespace FormsDI { public class MainPage : ContentPage { public MainPage () { var count = new Button { Text = "Click Me!", VerticalOptions = LayoutOptions.CenterAndExpand, HorizontalOptions = LayoutOptions.CenterAndExpand, }; count.Clicked += (sender, e) => { count.Text = DependencyService.Get<ICounter>( // DependencyFetchTarget.NewInstance DependencyFetchTarget.GlobalInstance ).CountUp() + " times clicked!"; }; Content = count; } } }
using System; using Xamarin.Forms; namespace FormsDI { public class App { public static Page GetMainPage () { return new MainPage (); } } }
MainPage.cs中のDependencyFetchTarget.NewInstance
とDependencyFetchTarget.GlobalInstance
をコメントアウトで切り替えながら実行してみてください。
DependencyFetchTarget.NewInstance
を指定するとボタンを押す度に新しいインスタンスが取得されるためカウントが進みませんが、DependencyFetchTarget.GlobalInstance
を指定すると毎回同じインスタンスを取得できるため、カウントが加算されていく様子を確認できると思います。