#c# #autofac
#c# #autofac
Вопрос:
У меня есть куча экземпляров класса TaskParametes, зарегистрированных в контейнере, например:
builder.Register(c => [some type instantiation]
)).Named<TaskParameters>("someTask").InstancePerDependency();
builder.Register(c => [some type instantiation]
)).Named<TaskParameters>("someOtherTask").InstancePerDependency();
Эти классы могут быть зарегистрированы в любом модуле приложения. Я хотел бы получить список доступных именованных экземпляров, чтобы отправить его клиенту, который должен создать экземпляр и выполнить его по имени.
Есть ли возможность получить список имен, фактически не создавая экземпляры типов? В настоящее время я изучаю ComponentRegistry IComponentContext, который я получаю из, var ctx = Container.Resolve<IComponentContext>();
, я на правильном пути?
Ответ №1:
Метаданные в данном случае более уместны, чем именование.
Для строго типизированного варианта определите интерфейс для хранения метаданных:
public interface ITaskMetadata
{
string Name { get; }
}
Затем свяжите метаданные во время сборки:
builder.Register(c => [some type instantiation]))
.As<TaskParameters>()
.WithMetadata<ITaskMetadata>(m =>
m.For(tm => tm.Name, "someTask"));
builder.Register(c => [some type instantiation]))
.As<TaskParameters>()
.WithMetadata<ITaskMetadata>(m =>
m.For(tm => tm.Name, "someOtherTask"));
( InstancePerDependency()
Опущен, поскольку это поведение по умолчанию.)
Затем компонент, которому необходимо проверить имена, может зависеть от IEnumerable<Lazy<T,TMetadata>>
вот так:
class SomeComponent : ISomeComponent
{
public SomeComponent(
IEnumerable<Lazy<TaskParameters,ITaskMetadata>> parameters)
{
// Here the names can be examined without causing instantiation.
}
}
При этом используются типы отношений, чтобы избежать необходимости искать что-либо в контейнере.
Обратите внимание, Lazy<,>
тип взят из .NET 4. Для получения подробной информации о достижении этого в .NET 3.5 и альтернативном синтаксисе смотрите Autofac wiki.
Комментарии:
1. Проблема с метаданными заключается в том, что я не могу запросить их из контейнера (есть
ResolveNamed
иResolveKeyed
, но нет отправки по метаданным). Я также не могу найти расширение «Для», оно в каком-то специальном пространстве имен? (AutoFac версии 2.4.4.705)2. Intellisense (ReSharper?) возникли проблемы с методом WithMetadata — он все равно должен скомпилироваться. Если вы хотите также разрешить эти обработчики из контейнера, пожалуйста, опубликуйте некоторые подробности этого сценария, в вашем вопросе говорится только о создании экземпляров путем делегирования клиентам. Для быстрого и грязного использования Named() может использоваться так же, как и с Metadata(). Приветствия!
Ответ №2:
Если имя службы важно для вашего приложения, возможно, это следует смоделировать в вашем коде. Например, у вас есть TaskParameters
; может быть, вы хотите что-то вроде:
public class Descriptor<T>
{
private readonly string _description;
private readonly Func<T> _create;
public Descriptor(string description, Func<T> create)
{
_description = description;
_create = create;
}
public string Description { get { return _description; } }
public T Create() { return _create(); }
}
И затем вы можете зарегистрировать дескрипторы для своих типов. Тогда вы могли бы легко вызвать
var descriptors = container.Resolve<IEnumerable<Descriptor<TaskParameters>>>();
Ответ №3:
Я не нашел никакого решения вместо запроса контекста:
var ctx = Container.Resolve<IComponentContext>();
var taskNames = ctx.ComponentRegistry.Registrations
.Select(c => c.Services.FirstOrDefault() as KeyedService)
.Where(s => s != null amp;amp; s.ServiceType == typeof (TaskParameters))
.Select(s => s.ServiceKey).ToList();
Кажется, что этот подход ничего не создает и не активирует.