Зарегистрируйте открытые универсальные типы для всех типов, реализующих некоторый интерфейс, в StructureMap - PullRequest
0 голосов
/ 25 июля 2011

Я хочу зарегистрировать все мои типы, реализующие IManager, чтобы их можно было использовать как тип T для универсального Lazy<T> класса.

Например:

public TetraRadioPropertyUpdater(Lazy<IRadioManager> lazyRadioManager)

Я использую самодельный сканер, потому что мои конкретные типы и интерфейсы являются внутренними, и поэтому я не могу использовать встроенный механизм сканирования StructureMap.

В первом операторе цикла регистрируются все мои IManager типы, подобные For<IRadioManager>().Singleton().Use<RadioManager>()

Также я хочу, чтобы они были зарегистрированы, чтобы их можно было использовать в качестве универсального типа для Lazy<T>, например For<Lazy<IRadioManager>().Use<Lazy<RadioManger>>()

 InterfaceScanner<IManager> interfaceScanner = new InterfaceScanner<IManager>();

 // managerMapping looks like:
 // { IRadioManager, RadioManager }
 // { ICallManager, CallManager }
 // .. more manager interface to plugin type pairs  
 foreach (KeyValuePair<Type, Type> managerMapping in interfaceScanner.Process())
 {
    // the key is the plugin type, value is the concrete type
    For(managerMapping.Key).Singleton().Use(managerMapping.Value);

    // something like this.. ?
    For(typeof(Lazy<>)).Singleton().Use(c => new Lazy(() => c.GetInstance(managerMapping.Value)));
 }

Возможно ли это?Как мне настроить его для StructureMap?

1 Ответ

2 голосов
/ 29 июля 2011

ОБНОВЛЕНИЕ: StructureMap v3 реализует это из коробки, поэтому этот трюк больше не нужен.


Вы можете явно зарегистрировать классы так:

container = new Container(x =>
{
    x.Scan(y =>
    {
        y.TheCallingAssembly();
        y.WithDefaultConventions();
    });

    x.For<Lazy<IFoo>>().Use(y => new Lazy<IFoo>(y.GetInstance<Foo>));
    x.For<Lazy<IBar>>().Use(y => new Lazy<IBar>(y.GetInstance<Bar>));
    x.For<Lazy<IBaz>>().Use(y => new Lazy<IBaz>(y.GetInstance<Baz>));
});

Было бы лучше, если бы это было сделано автоматически. В идеале неплохо было бы использовать следующий синтаксис.

x.For(typeof(Lazy<>)).Use(typeof(Lazy<>));

К сожалению, во время выполнения StructureMap попытается найти «самый жадный» конструктор для Lazy<T> и установить значение public Lazy(Func<T> valueFactory, bool isThreadSafe). Поскольку он не знает, что делать с логическим параметром isThreadSafe. Это бросит исключение. Вы можете явно указать StructureMap, какое значение использовать следующим образом.

x.For(typeof(Lazy<>)).Use(typeof(Lazy<>))
 .CtorDependency<bool>("isThreadSafe").Is(true);

Что остановит исключения и будет использовать значение "true" для параметра isThreadSafe. Документация для Lazy гласит, что режим безопасности потока конструктора Lazy(Func<T> valueFactory) по умолчанию равен LazyThreadSafetyMode.ExecutionAndPublication, что также можно получить, передав значение true в параметр isThreadSafe вышеприведенного конструктора, поэтому мы получим такое же поведение, как если бы мы вызвали конструктор, который мы на самом деле хотели использовать (например, Lazy(Func<T> valueFactory)). Подробнее о классе Lazy можно прочитать здесь .

Я понимаю, что это не дает прямого ответа на ваш вопрос относительно пользовательского класса сканера, но я надеюсь, что это даст вам хорошее начало.

...