[WPF]prism.unity(6.3.0)の簡単な実装サンプル①(登録~依存性注入まで)(RegisterInstance使用)


Prism関連
https://qiita.com/tera1707/items/4fda73d86eded283ec4f#prism%E9%96%A2%E9%80%A3wpfxaml

試した環境

モノ バージョン
VisualStudio 2017
Prism.Unity 6.3.0

やりたいこと

今のところDI(DependencyInjection)を使ったことがない。
DIを使えば、単体テストが楽になる複数名で開発するときに分担しやすくなるとか聞くが、具体的に何がどう楽になるのかがイメージがわかないので、実際にコードを書いてみて、なにが楽になるのか実感したい。

試した環境

モノ バージョン
VisualStudio 2017
Prism.Unity 6.3.0

サンプルを元に考える

こちらをベースにさせていただいています。

using Microsoft.Practices.Unity;
using System;

namespace ConsoleApp10
{
    class Program
    {
        static void Main(string[] args)
        {
            // DI コンテナを生成
            UnityContainer container = new UnityContainer();

            Console.WriteLine("[Main] 名前を指定してインスタンスを登録する。");

            // 名前を指定してインスタンスを登録(RegisterInstance()) // ここでDogやCatのコンストラクタが呼ばれる(newしたものを登録してるから)
            container.RegisterInstance<IAnimal>(new Dog());
            container.RegisterInstance<IAnimal>(new Dog(3));
            container.RegisterInstance<IAnimal>("Dog9", new Dog(9));
            container.RegisterInstance<IAnimal>("Dog12", new Dog(12));
            container.RegisterInstance<IAnimal>(new Cat());

            // 依存性を注入する
            Console.WriteLine("[Main] 依存性を注入する。");
            var person = container.BuildUp<Person>(new Person());

            // ペットを呼ぶ
            Console.WriteLine("[Main] ペットを呼ぶ。");
            person.CallPet();

            Console.ReadLine();
        }
    }

    // 動物インターフェース
    public interface IAnimal
    {
        void Cry();// 鳴き声を出力する
    }

    // ネコ(IAnimalインターフェースの実装)
    public class Cat : IAnimal
    {
        public Cat() => Console.WriteLine(" 猫 コンストラクタ");
        public void Cry() => Console.WriteLine("ニャ~");
    }

    // イヌ(IAnimalインターフェースの実装)
    public class Dog : IAnimal
    {
        private int Crynum = 0;// 鳴く回数

        public void Cry()
        {
            for (int i = 0; i < Crynum; i++)
                Console.WriteLine("バウ!");
        }

        public Dog()
        {
            Crynum = 0;
            Console.WriteLine(" 犬 コンストラクタ(引数なし)");
        }

        public Dog(int cryNum)
        {
            Crynum = cryNum;
            Console.WriteLine(" 犬 コンストラクタ(引数あり)");
        }
    }

    // 依存性を注入されるクラス
    public class Person
    {
        // 名前を指定すると、RegisterInstanceで名前を指定したものを使用する
        //[Dependency("Dog12")]
        // 名前を指定しないと、RegisterInstanceで名前を指定しておらず、一番後に登録されたものを使用する(あと勝ちで使われるっぽい)
        [Dependency]
        public IAnimal Pet { get; set; }

        // ペットを呼ぶ
        public void CallPet() => Pet.Cry();
    }
}

コードの流れ

  • 依存性の登録~注入までは、下記のような流れで行う。
    • UnityContainer container = new UnityContainer();DIコンテナを生成する
    • container.RegisterInstance<インターフェース>(new インターフェースを実装したクラス);でインスタンスをコンテナに登録する
    • container.BuildUp<注入先クラス>(new 注入先クラス());で、登録したコンテナを使って注入先クラスをnewすると同時に依存性(注入先で使うクラス達)を注入する
    • 注入先クラスで、注入されたクラス(のインスタンス)を使う

動作メモ

インスタンス化のタイミングについて

RegisterInstanceの引数には、外部でインスタンス化した、登録したいオブジェクトのインスタンスを指定する。そのため、RegisterInstanceが呼ばれたときには、すでに登録したいオブジェクトのインスタンス生成は完了している(= コンストラクタはすでに実行済み)。

注入される側の[Dependency]属性について

注入先クラスで注入されたものを使うときに、[Dependency("Dog9")]のように名前を指定すると、RegisterInstanceで名前を指定して登録されたもののうち、名前が一致するものを使用する。

[Dependency("Dog9")]
public IAnimal Pet { get; set; }

出力


注入先クラスで注入されたものを使うときに、[Dependency]のように名前を指定しないと、RegisterInstanceで名前を指定せず登録されたもののうち、最後に指定されたものを使用する。

[Dependency]
public IAnimal Pet { get; set; }

出力