かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Xamarin版PrismのDependencyServiceサポート機能

Prism.Formsは、基本的にUnity(DIコンテナのほう)を使ってます。 こいつを使うとインスタンスの組み立てとかをお任せ出来るので楽ちんなのです!

Prism.Formsでは、そんなUnityの機能を拡張して、DependencyServiceから取得するインスタンスを自動でインジェクションしてくれる機能を提供しています。

従来

普通はDependencyServiceを使うときは以下のような手順になります。

インターフェースの作成

まず、PCLの所にインターフェースを定義します。ここではプラットフォームの名前を返すインターフェースみたいなのを作りました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PrismUnityApp20.Models
{
    public interface IPlatformNameProvider
    {
        string GetName();
    }
}

各プラットフォームでの実装の作成

そして、次に各プラットフォームで実装を行います。 例えばAndroidだと以下のような感じですね。Dependency属性つけてるのがポイント。

using PrismUnityApp20.Models;
using Xamarin.Forms;

[assembly: Dependency(typeof(PrismUnityApp20.Droid.Models.AndroidPlatformNameProvider))]

namespace PrismUnityApp20.Droid.Models
{
    public class AndroidPlatformNameProvider : IPlatformNameProvider
    {
        public string GetName() => "Android";
    }
}

UWPだと以下のような感じ。

using PrismUnityApp20.Models;
using Xamarin.Forms;

[assembly: Dependency(typeof(PrismUnityApp20.UWP.Models.UWPPlatformNameProvider))]

namespace PrismUnityApp20.UWP.Models
{
    public class UWPPlatformNameProvider : IPlatformNameProvider
    {
        public string GetName() => "UWP";
    }
}

PCLでインスタンスを取得する

DependencyServiceのGetメソッドを使ってインスタンスを取得します。

var x = DependencyService.Get<IPlatformNameProvider>();
var name = x.GetName(); // メソッドを呼ぶと各プラットフォームの実装が呼ばれる

Prism.Formsの場合

最後のDependencyServiceのGetメソッドを呼ばなくてもよくなります。具体的には、使いたいクラスのコンストラクタの引数でインターフェースを受け取るようにするだけで自動的に各プラットフォーム固有の実装がインジェクションされます。

private IPlatformNameProvider PlatformNameProvider { get; }

public MainPageViewModel(INavigationService navigationService, IPlatformNameProvider pnp)
{
    // インスタンスをとっておいてよしなに使う
    this.PlatformNameProvider = pnp;
}

こうすることのメリットは、なんといってもユニットテストが簡単になるという点ですね! テスト時には、Mock実装を簡単に差し込めるようになります。すばらし。

あと、個人的にGetメソッドかっこわるいと思ってたので、この機能は歓迎です。