2014-11-28 7 views
0

Уверен, что я что-то пропустил.Как передать параметр конструктору с помощью Autofac

Я пытаюсь преобразовать код не DI, чтобы использовать autofac. У меня есть класс, который говорит об оборудовании, которое берет IP-адрес и абстрагирует интерфейс. У меня есть класс высокого уровня, который настраивает и управляет оборудованием. Я пытаюсь выяснить, как я могу создать несколько экземпляров этого класса, не передавая копию контейнера DI.

string FirstIP, SecondIP; 
//Set values from config/user etc. 

var FirstDevice = new HighLevelIF(new LowLevelIF(FirstIP)); 
var SecondDevice = new HighLevelIF(new LowLevelIF(SecondIP)); 

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

var FirstDevice = new HighLevelIFFactory.Create 
         (LowLevelIFFactory.Create 
         (FirstIP)); 

ответ

1

Если вам нужны эти IP-адреса должны быть разрешены по требованию, и они, вероятно, изменятся во время выполнения, abstract factory является лучшим выбором.

Если у вас есть список адресов, загруженных при запуске приложения, и вам просто нужно переключаться между этими экземплярами наиболее эффективным способом, вы можете использовать strategy pattern, что позволяет избежать инъекции контейнера в ваш класс.

Стратегия Пример

var builder = new ContainerBuilder(); 
// Register all instances of IDiscountCalculator 
builder.RegisterAssemblyTypes(this.GetType().Assembly) 
     .Where(t => typeof(IDiscountCalculator).IsAssignableFrom(t)); 
builder.Register<DiscountStrategy>().As<IDiscountStrategy>(); 
var container = builder.Build(); 
var strategy = container.Resolve<IDiscountStrategy>(); 

Console.WriteLine(strategy.GetDiscount("Regular", 10)); // 0 
Console.WriteLine(strategy.GetDiscount("Normal", 10)); // 1 
Console.WriteLine(strategy.GetDiscount("Special", 10)); // 5 

, который зависит от следующих типов:

public interface IDiscountStrategy 
{ 
    decimal GetDiscount(string userType, decimal orderTotal); 
} 

public class DiscountStrategy : IDiscountStrategy 
{ 
    private readonly IEnumerable<IDiscountCalculator> _discountCalculators; 

    public DiscountStrategy(IEnumerable<IDiscountCalculator> discountCalculators) 
    { 
     _discountCalculators = discountCalculators; 
    } 

    public decimal GetDiscount(string userType, decimal orderTotal) 
    { 
     var calculator = _discountCalculators.FirstOrDefault(x => x.AppliesTo(userType)); 
     if (calculator == null) return 0; 
     return calculator.CalculateDiscount(orderTotal); 
    } 
} 

public interface IDiscountCalculator 
{ 
    bool AppliesTo(string userType); 
    decimal CalculateDiscount(decimal orderTotal); 
} 

public class NormalUserDiscountCalculator : IDiscountCalculator 
{ 
    public bool AppliesTo(string userType) 
    { 
     return userType == "Normal"; 
    } 

    public decimal CalculateDiscount(decimal orderTotal) 
    { 
     return orderTotal * 0.1m; 
    } 
} 

public class SpecialUserDiscountCalculator : IDiscountCalculator 
{ 
    public bool AppliesTo(string userType) 
    { 
     return userType == "Special"; 
    } 

    public decimal CalculateDiscount(decimal orderTotal) 
    { 
     return orderTotal * 0.5m; 
    } 
} 

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

0

Вы можете использовать метод .WithParameter().

Например:

var builder = new ContainerBuilder(); 
builder.RegisterType<MyType>().As<IMyInterface>().WithParameter("paramName", "paramValue"); 

Edit: просто перечитывая свой вопрос. Возможно, вы хотите назвать свою регистрацию, а затем получить соответствующую?

Вы также можете сделать это:

var builder = new ContainerBuilder(); 
builder.RegisterType<MyType>().Named<IMyInterface>("MyName"); 
builder.RegisterType<MyType>().Named<IMyInterface>("MyOtherName"); 

var container = builder.Build(); 

// later 
container.ResolveNamed<IMyInterface>("MyName"); //gets MyName registration 
+0

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

+1

Я думаю, что это решение. Вы создаете интерфейс с фабрики с помощью метода, который принимает адрес времени выполнения. Почему бы вам не сделать это? –

0

Только для справки, я создал фабричные методы, передал их в конструкторы (которые автоматически запишутся для вас автоматически).

Затем у меня был «инициализированный» метод, который принял параметр IP камеры и использовал фабрики для создания объектов с соответствующими внутренними настройками. Работала хорошо для меня, но я уверен, что шаблон стратегии был бы действительным.

Смежные вопросы