С помощью метода расширения 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 проверять и диагностировать зарегистрированный компонент и его зависимости.
спасибо. Это действительно полезно. –