2016-04-14 4 views
2

Я принимаю удар, чтобы правильно внедрить DI в приложение Xamarin для Android, используя Autofac, но у меня возникли проблемы с пониманием того, как я должен обрабатывать экземпляры объектов, которым требуются данные, переданные в их конструктор. Например, одной из наших моделей просмотра нужна строка и направляющая, переданная ее конструктору. Что-то перспективное - Delegate Functions, предлагаемое Autofac. Вот где линия между Service Locator и DI, по-видимому, размывается, по крайней мере, на мой взгляд. Чтобы использовать функции делегата, вы должны вызвать container.Resolve, или, вернее, рекомендуется использовать IComponentContext.Resolve. Многие блоги рекомендуют не использовать Resolve вне начальной загрузки/главной точки входа. Что-то мне здесь не хватает? Есть ли лучший способ создания объектов с помощью DI? Я знаком с шаблоном Factory для создания объектов, но я чувствую, что теряю преимущества DI, идущего по этому маршруту, так как я возвращаюсь к ручному переходу в сервисах/объектах к вновь созданному объекту. Спасибо за любую обратную связь!Использование инъекции зависимостей (Autofac) и избежание шаблона локатора службы

+0

ли ViewModel быть инстанцирован с помощью инъекции или лет пытаются выяснить, как создается экземпляр вашего ViewModel, имея ViewModel принимать инъекционные параметры? –

+0

Последнее, что я пытаюсь сделать. Значения параметров конструктора для определенных режимов просмотра не известны до времени выполнения. – NastyNate

+0

«Значения параметров конструктора для определенных режимов просмотра не известны до времени исполнения». Это означает, что вы вводите значения времени выполнения в свои компоненты, это [анти-шаблон] (https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=99). – Steven

ответ

3

Это не рекомендуется позвонить container.Resolve(), чтобы использовать фабрику делегатов. Правильный путь показан на the delegate factories page that you already linked to:

public class Portfolio 
{ 
    Shareholding.Factory ShareholdingFactory { get; set; } 
    IList<Shareholding> _holdings = new List<Shareholding>(); 

    public Portfolio(Shareholding.Factory shareholdingFactory) 
    { 
    ShareholdingFactory = shareholdingFactory; 
    } 

    public void Add(string symbol, uint holding) 
    { 
    _holdings.Add(ShareholdingFactory(symbol, holding)); 
    } 
} 

Когда документы показывают явный вызов container.Resolve() вы должны понимать, что они не показывают лучшие практики, они просто доказав, что он может быть решен без кодирования целый новый класс (например, Portfolio), чтобы потреблять его.

+0

Спасибо за ваш ответ, теперь я чувствую себя немного глупо, потому что пропустил это. – NastyNate

0

Для того, чтобы использовать функции делегата вы должны вызвать container.Resolve

Нет, по крайней мере, не в этом случае.

Предполагая, что вы зарегистрировались Shareholding. Теперь вы можете задать зависимость от Func<Shareholding>, т.е. что-то шляпа возвращает Shareholding, когда вы его вызываете.

Но поскольку конструктор Shareholding имеет два параметра, он не может быть разрешен без предоставления этих параметров. Просто добавьте их в объявление следующим образом: Func<string, uint, Shareholding>. Теперь вы можете разрешить зависимость при поставке этих параметров.

Адрес better example.

+1

Благодарим вас за ответ. Хотя это актуально и полезно, default.kramer указал на то, что я пропустил в документации, которая ответила на мой вопрос, поэтому я выбрал его как ответ. – NastyNate

0

Я недавно (вчера) столкнулся с той же проблемой, с которой я столкнулся, используя объект ServiceClient, который вы видите в коде ниже. Этот объект обращается к вашему вопросу об использовании контейнера вне загрузочного файла. Я прочитал аргументы, которые говорят, что не пропускать контейнер, и я думаю, что они в основном действительны. Однако в моем случае класс ServiceClient представляет собой единственную точку входа в мой сервисный уровень, поэтому я счел целесообразным передать контейнер.

Пути я использую это на данный момент передать экземпляр ServiceClient в мой BaseController:

// In Global.asax.cs 
builder.RegisterControllers(typeof(MvcApplication).Assembly); 
builder.RegisterType<ServiceClient>().As<IServiceClient>(); 

BaseController:

public abstract class BaseController<T> : Controller where T :class 
{ 

    public IServiceClient ServiceClient { get; set; } 

    public BaseController(IServiceClient serviceClient) 
    { 
     ServiceClient = serviceClient; 
    } 
} 

В моем контроллере я могу решить, экземпляр, и вызов служба, которая использует неуправляемые ресурсы только с одной строкой:

myViewModel = await ServiceClient.OfType<ICustomerService>().TryAsync(x => x.GetCustomerByID(id)); 

ServiceClient:

public class ServiceClient : IServiceClient 
{ 
    private IComponentContext _container; 

    public ServiceClient(IComponentContext container) 
    { 
     _container = container; 
    } 

    public ServiceCallWrapper<T> OfType<T>() where T : class, IDisposable 
    { 
     return new ServiceCallWrapper<T>(_container); 
    } 
} 

public class ServiceCallWrapper<T> : IServiceCallWrapper<T> where T : class, IDisposable 
{ 
    private IComponentContext _container; 

    internal ServiceCallWrapper(IComponentContext container) 
    { 
     _container = container; 
    } 

    public void Try(Action<T> method) 
    { 
     // consider try/catch/log/throw here 
     using (T client = _container.Resolve<T>()) 
     { 
      method(client); 
     } 
    } 

    public TResult Try<TResult>(Func<T, TResult> method) 
    { 
     using (T client = _container.Resolve<T>()) 
     { 
      return method(client); 
     } 
    } 

    public async Task TryAsync(Func<T, Task> method) 
    { 
     using (T client = _container.Resolve<T>()) 
     { 
      await method(client); 
     } 
    } 

    public async Task<TResult> TryAsync<TResult>(Func<T, Task<TResult>> method) 
    { 
     using (T client = _container.Resolve<T>()) 
     { 
      return await method(client); 
     } 
    } 
} 
Смежные вопросы