SimpleInjector Lazy in a Reflection - PullRequest
0 голосов
/ 28 мая 2020

Мы используем SimpleInjector в качестве инжектора зависимостей, и мы регистрируем все типы интерфейсов, используя итерацию сборки.

public static void RegisterInterfaceTypes(this Container container, Assembly assembly)
{
    assembly.GetExportedTypes()
        .Select(t => new {
            Type = t,
            Interface = t.GetInterfaces().FirstOrDefault()
        })
        .ToList()
        .ForEach(t =>
        {
            container.Register(t.Interface, t.Type, Lifestyle.Transient);
        });
}

У нас также есть ленивые классы для регистрации. Мы можем зарегистрировать эти классы, как показано ниже, один за другим. Но мы хотим зарегистрировать все ленивые типы с аналогичной итерацией, используя отражение.

container.Register(() => new Lazy<ICommonBusiness>(container.GetInstance<CommonBusiness>));

1 Ответ

1 голос
/ 28 мая 2020

Вы можете использовать метод расширения ResolveUnregisteredType для выполнения регистраций в последнюю минуту для разрешения Lazy<T> зависимостей:

Источник :

public static void AllowResolvingLazyFactories(this Container container)
{
    container.ResolveUnregisteredType += (sender, e) =>
    {
        if (e.UnregisteredServiceType.IsGenericType &&
            e.UnregisteredServiceType.GetGenericTypeDefinition() == typeof(Lazy<>))
        {
            Type serviceType = e.UnregisteredServiceType.GetGenericArguments()[0];

            InstanceProducer registration = container.GetRegistration(serviceType, true);

            Type funcType = typeof(Func<>).MakeGenericType(serviceType);
            Type lazyType = typeof(Lazy<>).MakeGenericType(serviceType);

            var factoryDelegate = Expression.Lambda(funcType, registration.BuildExpression()).Compile();

            var lazyConstructor = (
                from ctor in lazyType.GetConstructors()
                where ctor.GetParameters().Length == 1
                where ctor.GetParameters()[0].ParameterType == funcType
                select ctor)
                .Single();

            var expression = Expression.New(lazyConstructor, Expression.Constant(factoryDelegate));

            var lazyRegistration = registration.Lifestyle.CreateRegistration(
                serviceType: lazyType,
                instanceCreator: Expression.Lambda<Func<object>>(expression).Compile(),
                container: container);

            e.Register(lazyRegistration);
        }
    };
}

Использование:

container.AllowResolvingLazyFactories();

Но обратите внимание на предупреждения из документации:

Предупреждение: регистрация [Lazy<T>] по умолчанию является запахом дизайна. Использование [Lazy<T>] усложняет отслеживание вашего дизайна, а вашу систему труднее поддерживать и тестировать. В вашей системе должно быть только несколько из них [...] самое большее. Если в вашей системе много конструкторов, зависящих от [Lazy<T>], внимательно посмотрите на свою стратегию зависимостей. В статье , следующей за , подробно рассказывается о том, почему [это] запах дизайна.

Предупреждение: [...] конструкторы ваших компонентов должны быть простыми, надежными и быстрыми (как объяснено в этой записи блога Марка Симанна). Это устранит необходимость в ленивой инициализации. Для получения дополнительной информации о создании приложения и конфигурации контейнера, которые могут быть успешно проверены, прочтите Как проверить конфигурацию контейнера.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...