Представим себе код, который был написан без применения принципов IoC.
Например такой

public class AccountManager
{
    public void CreateAccount(string userName, string password)
    {
        var accountStore = new AccountStore();
        accountStore.AddNewAccount(userName, password);
    }

    public bool Authenticate(string userName, string password)
    {
        var accountStore = new AccountStore();
        if (accountStore.IsValidAccount(userName, password))
        {
            Session.CurrentSession.SetAuthToken(userName);
            return true;
        }
        else
        {
            return false;
        }
    }

    public bool IsUserInRole(string userName, string roleName)
    {
        var roleStore = new RoleStore();
        return roleStore
                .GetRolesForUser(userName)
                .Contains(roleName);
    }
}

Классы AccountStore и RoleStore – это персистентные хранилища, а класс Session хранит информацию о текущем сеансе работы пользователя.

Класс AccountManager применяется во многих местах, поэтому  мы не можем сразу вынести все зависимости в конструктор.

Поэтому сначала немного отрефакторим класс AccountManager и вынесем зависимости в открытые свойства, чтобы через них можно было подпихивать зависимости.

public class AccountManager
{
    [Dependency]
    public AccountStore AccountStore { get; set; }

    [Dependency]
    public RoleStore RoleStore { get; set; }

    [Dependency("GetCurrentSession")]
    public Func<Session> GetCurrentSession { get; set; }

    public AccountManager()
    {
        AccountStore = new AccountStore();
        RoleStore = new RoleStore();
        GetCurrentSession = () => Session.CurrentSession;
    }

    public void CreateAccount(string userName, string password)
    {
        AccountStore.AddNewAccount(userName, password);
    }

    public bool Authenticate(string userName, string password)
    {
        if (AccountStore.IsValidAccount(userName, password))
        {
            GetCurrentSession().SetAuthToken(userName);
            return true;
        }
        return false;
    }

    public bool IsUserInRole(string userName, string roleName)
    {
        return RoleStore
                .GetRolesForUser(userName)
                .Contains(roleName);
    }
}

В этом коде атрибутами сразу обозначены зависимости.  Эти атрибуты будет анализировать Unity при инъекции зависимостей.
Так как при инъекции компоненты подбираются по типу, то для функцции GetCurrentSession желательно указать дополнительный строковый идентификатор.

Теперь будем прикручивать IoC-контейнер.
Нам сначала понадобится создать синглтон контейнера Unity.
Многие, в том числе и я, считают синглтоны злом, но в данном случае немного зла необходимо.

public static class UnitySingleton
{
    static IUnityContainer _instance = new UnityContainer();

    public static UnitySingleton()
    {
	//Здесь будем конфигурировать контейнер
        _instance
            .RegisterType<AccountStore>()
            .RegisterType<RoleStore>()
            .RegisterInstance<Func<Session>>(
                    "GetCurrentSession",
                    () => Session.CurrentSession);
    }

    public static IUnityContainer Instance
    {
        get
        {
            return _instance;
        }
    }
}

Для регистрации метода получения текущей сессии используется RegisterInstance. Этот метод помещает в контейнер экземпляр объекта, указанный параметром. Контейнер удерживает этот объект все время, но с помощью LifetimeManager это поведение можно изменить.

Теперь в конструкторе AccountManager напишем только одну строчку

public AccountManager()
{
    UnitySingleton.Instance.BuildUp(this);
}

После таких преобразований можно выделять интерфейсы классов, используемых внутри AccountManager чтобы ослабить зависимости между классами, а также проводить аналогичный рефакторинг для классов, использующих AccountManager.

Когда сам класс AccountManager нигде не будет инстанцироваться явно через new, а только доставаться из контейнера, тогда можно будет рефакторить AccountManager, чтобы он получал  все зависимости через конструктор.

Теги : Unity, .NET, IoC-контейнер, рефакторинг