Насколько я знаю, вам необходимо создать пользовательский IRegistrationConvention
, найденный в пространстве имен StructureMap.Graph
.
Реализация соглашения
public class ServiceDiscoveryConvention
: StructureMap.Graph.IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
// check if type has attribute
// add to registry using the registry variable
}
}
Добавить соглашение к сканеру
Scan(cfg =>
{
cfg.TheCallingAssembly(); // or whatever assemblies you are scanning
cfg.Convention<ServiceAttributeConvention>();
});
Замечания
Если вы свободны в своем решении, вы можете использовать интерфейсы вместо атрибутов,Используя интерфейс, вы можете предоставить общий контракт для всех классов, и с ними гораздо проще работать, когда проект расширяется.
Атрибуты имеют тенденцию распространяться по всему коду, их рефакторинг может быть реальнымболь.Интерфейсы имеют гораздо лучшую инструментальную поддержку, когда дело доходит до рефакторинга.
Я использую интерфейсы для аналогичной задачи (система плагинов), соглашение вроде
public class TypeScanner<T> : IRegistrationConvention
{
private static readonly Type PluginInterface = typeof(T);
public void Process(Type type, Registry registry)
{
if (type.IsAbstract || type.BaseType == null) return;
if (PluginInterface.IsAssignableFrom(type) == false) return;
registry.For(PluginInterface).Singleton().Add(instance);
}
}
будет таким же:
Scan(cfg =>
{
cfg.TheCallingAssembly(); // or whatever assemblies you are scanning
cfg.Convention<TypeScanner<IYourService>>();
});
Если ваше соглашение принимает аргументы конструктора, вы можете использовать With
:
Scan(cfg =>
{
cfg.TheCallingAssembly(); // or whatever assemblies you are scanning
var convention = new SomeConvention(x,y,z);
cfg.With(convention);
});