反射中的 SimpleInjector 懒惰

SimpleInjector Lazy in a Reflection

我们正在使用 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>));

您可以使用 ResolveUnregisteredType 扩展方法进行最后一分钟的注册以解决 Lazy<T> 依赖项:

Source:

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();

但请注意文档中的 the warnings

Warning: Registering [Lazy<T>] by default is a design smell. The use of [Lazy<T>] makes your design harder to follow and your system harder to maintain and test. Your system should only have a few of those [...] at most. If you have many constructors in your system that depend on a [Lazy<T>], please take a good look at your dependency strategy. The following article goes into details about why [this is] a design smell.

Warning: [...] the constructors of your components should be simple, reliable and quick (as explained in this blog post by Mark Seemann). That would remove the need for lazy initialization. For more information about creating an application and container configuration that can be successfully verified, please read the How To Verify the container’s configuration.