Может кто-нибудь объяснить магию, происходящую в методе Prism's resol <>? - PullRequest
0 голосов
/ 20 июля 2009

У меня есть CustomersModule.cs со следующим методом Initialize ():

public void Initialize()
{
    container.RegisterType<ICustomersRepository, CustomersRepository>(new ContainerControlledLifetimeManager());
    CustomersPresenter customersPresenter = this.container.Resolve<CustomersPresenter>();

}

Класс , который я определяю из контейнера, выглядит следующим образом:

class CustomersPresenter
{
    private CustomersView view;
    private ICustomersRepository customersRespository;

    public CustomersPresenter(CustomersView view, 
        ICustomersRepository customersRepository, 
        TestWhatever testWhatever)
    {
        this.view = view;
        this.customersRespository = customersRepository;
    }
}

TestWh независимо от того, класс - это просто фиктивный класс , который я создал:

public class TestWhatever
{
    public string Title { get; set; }

    public TestWhatever()
    {
        Title = "this is the title";
    }

}

И все же контейнер радостно разрешает CustomersPresenter, хотя Я никогда не регистрировал его , а также контейнер каким-то образом находит TestWh независимо, создает его экземпляр и внедряет его в CustomersPresenter.

Я был очень удивлен, осознав это , поскольку нигде не мог найти документацию Prism, в которой прямо указано, что контейнер был настолько автоматическим.

Так что это здорово, но что еще делает контейнер, о котором я не знаю, т. Е. Что еще он может делать, о чем я не знаю? Например, могу ли я внедрить классы из других модулей, и если модули будут загружены, контейнер введет их, а если нет, то добавит ноль?

Ответы [ 2 ]

3 голосов
/ 20 июля 2009

В этом нет ничего волшебного. Вы указываете конкретные типы, поэтому, естественно, они разрешимы, потому что если у нас есть объект Type, мы можем вызвать конструктор.

class Fred { };

Fred f1 = new Fred();

Type t = typeof(Fred);

Fred f2 = (Fred)t.GetConstructor(Type.EmptyTypes).Invoke(null);

Последняя строка выше - это то, что происходит, тип t был найден с помощью typeof в параметре типа, который вы задаете для Resolve.

Если тип не может быть создан новым (потому что он находится в некоторой неизвестной отдельной кодовой базе), вы не сможете передать его в качестве параметра типа для Resolve.

Во втором случае это инжекция конструктора, но это все еще известный конкретный конструируемый тип. С помощью отражения инфраструктура Unity может получить массив всех типов параметров для конструктора. Тип TestWhatever является конструируемым, поэтому нет никакой двусмысленности или сложности в отношении того, что конструировать.

Что касается вашего беспокойства по поводу отдельных модулей (сборок), если вы переместите TestWhatever в другую сборку, это не изменит строки написанного вами кода; это просто будет означать, что вам нужно добавить ссылку на другую сборку, чтобы получить эту сборку. И тогда TestWhatever по-прежнему является однозначно ссылочным конструируемым типом, поэтому он может быть создан Unity.

Другими словами, если вы можете ссылаться на тип в коде, вы можете получить объект Type, и поэтому во время выполнения он будет непосредственно конструируемым.

Ответ на комментарий:

Если вы удалите класс TestWhatever, вы получите ошибку во время компиляции, потому что вы ссылаетесь на этот тип в своем коде. Таким образом, невозможно получить время выполнения, выполнив это.

Разъединение все еще действует в этой схеме, поскольку вы можете зарегистрировать конкретный экземпляр TestWhatever, поэтому каждый вызов Resolve<TestWhatever>() будет получать один и тот же экземпляр, а не создавать новый.

2 голосов
/ 13 сентября 2009

Причина, по которой это работает, заключается в том, что Unity предназначена для этого. Когда вы решаете с конкретным типом, Unity ищет, может ли он разрешиться из контейнера. Если это невозможно, тогда он просто отправляет экземпляр типа, разрешающий его зависимости. Это действительно довольно просто.

...