Я использую Unity в Регистрация по соглашению механизм по следующему сценарию:Почему тип зарегистрирован дважды, когда указан менеджер времени жизни?
public interface IInterface { }
public class Implementation : IInterface { }
Учитывая Implementation
класс и его интерфейс Я бегу RegisterTypes
следующим образом:
unityContainer.RegisterTypes(
new[] { typeof(Implementation) },
WithMappings.FromAllInterfaces,
WithName.Default,
WithLifetime.ContainerControlled);
После этого звонок, unitContainer
содержит три регистраций:
IUnityContainer
->IUnityContainer
(ок)IInterface
->Implementation
(ок)Implementation
->Implementation
(???)
Когда я изменить вызов следующим образом:
unityContainer.RegisterTypes(
new[] { typeof(Implementation) },
WithMappings.FromAllInterfaces,
WithName.Default);
Контейнер содержит только две регистрации:
IUnityContainer
->IUnityContainer
(ок)IInterface
->Implementation
(ок)
(это желаемое поведение).
После заглядывания в Unity's source code, я заметил, что есть некоторые недоразумения относительно того, как должно работать IUnityContainer.RegisterType
.
Метод RegisterTypes
работает следующим образом (комментарии указывают на то, что являются значения в сценариях, представленных выше):
foreach (var type in types)
{
var fromTypes = getFromTypes(type); // { IInterface }
var name = getName(type); // null
var lifetimeManager = getLifetimeManager(type); // null or ContainerControlled
var injectionMembers = getInjectionMembers(type).ToArray(); // null
RegisterTypeMappings(container, overwriteExistingMappings, type, name, fromTypes, mappings);
if (lifetimeManager != null || injectionMembers.Length > 0)
{
container.RegisterType(type, name, lifetimeManager, injectionMembers); // !
}
}
Поскольку fromTypes
не пусто, то RegisterTypeMappings
добавляет одно отображение типа: IInterface
->Implementation
(верный).
Тогда, в случае, когда lifetimeManager
не пусто, то код пытается изменить менеджер пожизненная следующим вызовом:
container.RegisterType(type, name, lifetimeManager, injectionMembers);
имя этой функции полностью ввести в заблуждение, потому что the documentation четко говорится, что:
RegisterType a LifetimeManager для данного типа и имени с контейнером. Для этого типа не выполняется сопоставление типов.
К сожалению, не только имя вводит в заблуждение, но и документация неверна. При отладке этого кода я заметил, что при отсутствии сопоставления с type
(Implementation
в приведенных выше сценариях) он добавляется (как type
->type
), поэтому мы в итоге получаем три регистраций в первом сценарии ,
Я скачал источники единства, чтобы решить эту проблему, но я нашел следующее испытание блока:
[TestMethod]
public void RegistersMappingAndImplementationTypeWithLifetimeAndMixedInjectionMembers()
{
var container = new UnityContainer();
container.RegisterTypes(new[] { typeof(MockLogger) }, getName: t => "name", getFromTypes: t => t.GetTypeInfo().ImplementedInterfaces, getLifetimeManager: t => new ContainerControlledLifetimeManager());
var registrations = container.Registrations.Where(r => r.MappedToType == typeof(MockLogger)).ToArray();
Assert.AreEqual(2, registrations.Length);
// ...
- что почти точно мой случай, и приводит к моему вопросу:
Почему это ожидалось? Это концептуальная ошибка, единичный тест, созданный для соответствия существующему поведению, но не обязательно правильный, или я пропущу что-то важное?
Я использую Unity v4.0.30319.
Часть о том, что вынуждена иметь несколько экземпляров менеджера жизненного цикла по умолчанию, когда есть несколько интерфейсов, кажется сильным аргументом и единственной конкретной до сих пор причиной. Благодаря! – BartoszKP