2016-05-09 4 views
3

У меня есть вопрос относительно ContextDependentExtensions из SimpleInjector библиотеки. Мы имеем следующее расширение, чтобы добавить возможность добавления элементов в инжектор с некоторым контекстом: ContextDependentExtensionsContextDependent instance as Singleton in Simple Injector

Пример:

var container = new Container(); 
container.RegisterWithContext(logger => new SimpleLogger("Logger Constructor Parameter")); 

Вот один интерес линия: Should always be transient!

Итак, что же это значит? И можем ли мы использовать здесь Lifestyle.Singleton или Lifestyle.Scoped образ жизни?

Может кто-нибудь объяснить это мне? Спасибо заранее.

ответ

2

С помощью метода расширения RegisterWithContext вы регистрируете предикат, который позволяет создавать экземпляр, используя информацию о потребляющем компоненте. Эта информация предоставляется предикату методом расширения.

Поскольку это означает, что вы можете создать совершенно другой экземпляр для каждого типа потребления, что делает регистрацию чем-то еще, но временным, может привести к очень странному поведению. Представьте себе, например, регистрацию в ILogger абстракции, где вы создаете Logger<T> реализацию где T является типом потребляющей компоненты:

container.RegisterWithContext(c => 
    (ILogger).container.GetInstance(
     typeof(Logger<>).MakeGenericType(c.ImplementationType))); 

Если бы этим регистрационного синглтон, это может вызвать проблемы, даже если потребитель компоненты являются одноэлементными, поскольку один и тот же экземпляр будет вводиться каждому потребителю; в то время как каждому потребителю потребуется свой собственный экземпляр, потому что они требуют своей собственной закрытой родовой версии, а именно: Logger<Consumer1>, Logger<Consumer2>, Logger<Consumer3> и т. д. Вместо этого очень потребитель получит тот же экземпляр; экземпляр, созданный для первого разрешенного потребителя. Это очевидно ужасно.

Эта же проблема будет существовать и при использовании экземпляров Scoped; вы получите тот же экземпляр на весь срок действия, который обычно не тот, который вы хотите; экземпляр должен быть зависимым от контекста.

Это серьезное ограничение метода расширения RegisterWithContext, которое было предоставлено с помощью документации Simple Injector v2. Поскольку это было слишком ограничивающим, Simple Injector v3 теперь содержит встроенный метод RegisterConditional, который заменяет метод расширения RegisterWithContext. Документы v3 никогда не ссылаются на RegisterWithContext, и мы бы советовали вместо этого использовать RegisterWithContext.

Документация describes как использовать RegisterConditional и показывает следующий пример:

container.RegisterConditional(
    typeof(ILogger), 
    c => typeof(Logger<>).MakeGenericType(c.Consumer.ImplementationType), 
    Lifestyle.Singleton, 
    c => true); 

Поскольку предикат этой регистрации возвращает true, регистрация не является действительно условным, а просто контекстная.

Используя этот код, вы можете вернуть Logger<T>, относящийся к компоненту-потребителю, но при этом убедитесь, что не более одного экземпляра каждого закрытого типа Logger<T>; таким образом, одноэлементный.

Основное отличие между новыми RegisterConditional и старым RegisterWithContext состоит в том, что вы не можете предоставить делегат фабрики для создания экземпляров. С помощью RegisterConditional Simple Injector контролирует создание экземпляров (вместо вашего делегата), и это позволяет полностью создавать типы конвейера в конвейере и позволяет Simple Injector проверять и диагностировать зарегистрированный компонент и его зависимости.

+0

спасибо. Это действительно полезно. –

Смежные вопросы