読者です 読者をやめる 読者になる 読者になる

ぴーさんログ

だいたいXamarin.Formsのブログ

Xamarin.FormsのDependencyService.Get<T>()はSingletonなのか?

DependencyServiceとは

DependencyServiceはXamarin 3.0で追加されたXamarin.Formsに含まれる、依存性注入のための仕組みです。ドキュメントはこちら。

Accessing Native Features via the DependencyService

DependencyServiceの使い方

ドキュメントを要約すると以下のような感じです。

  1. Sharedプロジェクトでインターフェースを定義。
  2. 各プラットフォームのプロジェクトでインターフェースを実装。
  3. assemblyに付けるDependencyという属性でインターフェースの実装クラスを宣言。
  4. 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.NewInstanceDependencyFetchTarget.GlobalInstanceコメントアウトで切り替えながら実行してみてください。

DependencyFetchTarget.NewInstanceを指定するとボタンを押す度に新しいインスタンスが取得されるためカウントが進みませんが、DependencyFetchTarget.GlobalInstanceを指定すると毎回同じインスタンスを取得できるため、カウントが加算されていく様子を確認できると思います。

サンプルダウンロード

GitHubに置いておきますのでこちらからどうぞ。