#c# #dependency-injection #inversion-of-control #instantiation #structuremap
#c# #внедрение зависимости #инверсия управления #создание экземпляра #structuremap
Вопрос:
Привет, в Autofac я могу это сделать:
public class Service1_Client
{
private const string ServiceName = "Service1";
Func<string, RabitMqClient> _clientFunc;
public Service1_Client(Func<string, RabitMqClient> clientFunc)
{
_clientFunc = clientFunc;
}
public IList<object> GetData()
{
return _clientFunc(this.ServiceName).Get<IList<object>>();
}
}
public class Service2_Client
{
private const string ServiceName = "Service2";
Func<string, RabitMqClient> _clientFunc;
public Service2_Client(Func<string, RabitMqClient> clientFunc)
{
_clientFunc = clientFunc;
}
public IList<object> GetData()
{
return _clientFunc(this.ServiceName).Get<IList<object>>();
}
}
public class RabitMqClient
{
private IConnectionFactory _connectionFactory;
private string _baseServiceName;
public RabitMqClient(IConnectionFactory connectionFactory, string baseServiceName)
{
_connectionFactory = connectionFactory;
_baseServiceName = baseServiceName;
}
public TResult Get<TResult>()
{
string topicName = this.GetTopicName();
///Connect to the channel that uses the topic and ask for data...
}
private string GetTopicNAme()
{
/// this should be an algoritam for getting the topic from the speccified baseServiceName (I have omitted the details)
return this._baseServiceName;
}
}
Теперь объяснение:
В принципе, у меня есть класс (RabitMqClient), который зависит от двух параметров:
- ConnectionFactory (IConnectionFactory )
- baseServiceName (строка)
Эти параметры используются для подключения к серверу RabbitMQ. Теперь я использую разделы в RabbitMQ для диверсификации сервисов, и для получения правильного раздела используется строковый параметр baseServiceName. Ожидается, что вызывающий объект (Service1_Client, Service2_Client) предоставит строковый параметр baseServiceName.
В Autofac я могу зарегистрировать этот класс следующим образом:
builder.Register((context, parameters) =>
{
var param = parameters.First() as Autofac.TypedParameter;
return new HcRabbitMqClient(
context.Resolve<IConnectionFactory>(),param.Value.ToString());
}).AsSelf().InstancePerDependency();
Это сообщает Autofac, что при запросе этого класса позвольте Autofac разрешить первый параметр, но вызывающий объект предоставит второй (строковый) параметр на сайте вызова. Затем этот строковый параметр будет помещен в значение параметров.
Использование этого можно увидеть в приведенном выше коде (Service1_Client, Service2_Client) Методы getData();
Как это сделать в StructureMap?
Комментарии:
1. Не могли бы вы немного подробнее рассказать о том, как это используется в вашем приложении с Autofac, пожалуйста?
Ответ №1:
Как насчет расширения этого заводского шаблона?
public interface IRabitMqClientFactory
{
IRabitMqClientFactory Create(string baseServiceName);
}
public class RabitMqClientFactory : IRabitMqClientFactory
{
public RabitMqClientFactory(IConnectionFactory connectionFactory){
_connectionFactory = connectionFactory;
}
public IRabitMqClientFactory Create(string baseServiceName)
{
_baseServiceName = baseServiceName;
}
}
а затем просто
public class Service1_Client
{
private const string ServiceName = "Service1";
private RabbitMqClient _rabbitMqClient;
public Service1_Client(IRabitMqClientFactory rabitMqClientFactory)
{
_rabbitMqClient = rabitMqClientFactory.Create(ServiceName);
}
public IList<object> GetData()
{
return _rabbitMqClient.Get<IList<object>>();
}
}
это также немного более читабельно, чем наличие сложной логики внутри вашего IoC.
Комментарии:
1. Хорошо, это решение даже лучше, чем в моем примере. Спасибо
Ответ №2:
Попробуйте это
For<Func<string, RabitMqClient>>().Use(cstr => new RabitMqClient(cstr));
Комментарии:
1. Хорошо, это работает для 1 параметра, но что, если у меня их больше? ie. Func<строка,int,string,RabitMqClient>
2. Затем добавьте параметры, подобные этому
For<Func<string, int, RabitMqClient>>().Use((cstr, int) => { return new RabitMqClient(cstr, int) });