Используя StructureMap для создания классов по имени? - PullRequest
2 голосов
/ 01 апреля 2010

Как я могу использовать StructureMap для разрешения соответствующей реализации интерфейса на основе имени, хранящегося в атрибуте?

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

Для иллюстрации:

[Configuration("header")]
public class HeaderWidget : IWidget { }

[Configuration("linegraph")]
public class LineGraphWidget : IWidget { }

При обработке моего (XML) файла конфигурации я хочу получить экземпляр соответствующего конкретного класса на основе имени элемента, который я обрабатываю.

public IWidget CreateWidget(XElement definition)
{
    var kind = definition.Name.LocalName;
    var widget = // What goes here?
    widget.Configure(definition);
    return widget;
}

Каждое определение должно приводить к созданию другого виджета - мне не нужно или я хочу, чтобы экземпляры были общими.

В прошлом я написал множество кода для ручного выполнения подобных задач, включая написание собственного контейнера IoC «сверните свои собственные» для одного проекта. Однако одна из моих целей в этом проекте - стать опытным в StructureMap, а не изобретать велосипед.

Я думаю, что мне уже удалось настроить автоматическое сканирование сборок, чтобы StructureMap знал обо всех моих реализациях IWidget:

public class WidgetRegistration : Registry
{
    public WidgetRegistration()
    {
        Scan(
            scanner =>
            {
                scanner.AssembliesFromApplicationBaseDirectory();
                scanner.AddAllTypesOf<IWidget>();
            });
    }
}

Однако, это не регистрация имен моих виджетов в StructureMap. Что мне нужно добавить, чтобы мой сценарий работал?

(Хотя я пытаюсь использовать StructureMap в этом проекте, ответ, показывающий мне, как решить эту проблему с помощью другого инструмента DI / IoC, все равно будет полезен.)

Update

Я почти уверен, что сторона потребления связана с вызовом GetNamedInstance следующим образом:

public IWidget CreateWidget(XElement definition)
{
    var kind = definition.Name.LocalName;
    var widget = ObjectFactory.GetNamedInstance<IWidget>(kind);
    widget.Configure(definition);
    return widget;
}

Итак, оставшаяся часть головоломки состоит в том, как автоматически регистрировать типы в моем классе WidgetRegistration.

Ответы [ 2 ]

1 голос
/ 05 апреля 2010

Вот где я остановился - получается, что все, что мне нужно, поддерживается из коробки StructureMap.

Мой регистрационный класс берет на себя всю грязную работу:

public class DashboardRegistration : Registry
{
    public DashboardRegistration()
    {
        Scan(
            scanner =>
            {
                scanner.AssembliesFromApplicationBaseDirectory();
                scanner.AddAllTypesOf<IDisplay>()
                    .NameBy(DashboardXml.DisplayElement);
                scanner.AddAllTypesOf<IDataSource>()
                    .NameBy(DashboardXml.DataSourceElement);
            });
    }
}

.NameBy() принимает делегата, который предоставляет требуемое имя.

Соответствующие методы класса DashboardXml выглядят следующим образом (сокращенный код):

public static class DashboardXml
{
    ...

    public static string DataSourceElement(Type type)
    {
        const string DataSourceSuffix = "DataSource";

        string result = type.Name;
        if (result.EndsWith(DataSourceSuffix))
        {
            result 
                = result.Substring(0, result.Length - DataSourceSuffix.Length);
        }

        return result.ToLowerInvariant();
    }

    public static string DisplayElement(Type type)
    {
        const string DisplaySuffix = "Display";

        string result = type.Name;
        if (result.EndsWith(DisplaySuffix))
        {
            result 
                = result.Substring(0, result.Length - DisplaySuffix.Length);
        }

        return result.ToLowerInvariant();
    }
}
1 голос
/ 01 апреля 2010

Мы внедрили пользовательский сканер:

    public class WidgetScanner : ITypeScanner
{
    public void Process(Type type, PluginGraph graph)
    {

Затем используйте сканирование:

        Scan(y =>
        {
            y.AddAllTypesOf(typeof(IWidget));
            y.Assembly(Assembly.GetExecutingAssembly().FullName);
            y.With<WidgetScanner>();
        });

.. и получить экземпляр:

_container.GetInstance<IWidget>(name)
...