有什么办法可以更快地解决依赖关系?

Any way to resolve dependencies sooner?

解析服务时,使用和不使用自动生成的工厂是有区别的。例如,如果我有这些 类:

public class A {
    public delegate A Factory();
    public A(B someDependency) {}
}

public class B {
    public B(String s) {}
}

public class AFactory {
    private readonly Func<B> _b;

    public AFactory(Func<B> b) {
        _b = b;
    }

    public A Create() {
        return new A(_b());
    }
}

并注册他们:

var cb = new ContainerBuilder();
cb.RegisterType<A>();
cb.RegisterType<AFactory>();
var c = cb.Build();

调用 c.Resolve<AFactory>() 将立即产生 DependencyResolutionException。调用 c.Resolve<A.Factory>() 将 return 一个将在调用时抛出 DependencyResolutionException 的委托。

在我看来 c.Resolve<AFactory>() 提供的行为更可取,因为在解析服务时会抛出异常,而不是在将来实际使用服务时抛出异常。我正在寻找可以应用于我项目中所有注册的通用解决方案。

有什么方法可以改变我示例中 c.Resolve<A.Factory>() 的行为,使其立即抛出异常?

It seems to me that the behavior provided by c.Resolve() is more desirable since the exception will be thrown when resolving a service

解析委托将导致惰性操作。这意味着具体的解析操作可能会在初始解析之后进行。在初始解析和最终解析之间,容器可能会发生变化。

看下面的例子:

class Program
{
    static void Main(string[] args)
    {
        ContainerBuilder builder = new ContainerBuilder();
        builder.RegisterType<Foo>().AsSelf();
        builder.RegisterType<Bar1>().As<IBar>();

        IContainer container = builder.Build();
        Foo foo = container.Resolve<Foo>();

        foo.Do(); // ==> DependencyResolutionExtension 

        // update the container with the Pouet type
        builder = new ContainerBuilder();
        builder.RegisterType<Pouet>().AsSelf();
        builder.Update(container);

        foo.Do(); // OK


        // update the container with another IBar
        builder = new ContainerBuilder();
        builder.RegisterType<Bar2>().As<IBar>();
        builder.Update(container);

        foo.Do(); // OK 
    }
}

public class Foo
{
    public Foo(Func<IBar> barFactory)
    {
        this._barFactory = barFactory;
    }

    private readonly Func<IBar> _barFactory;

    public void Do()
    {
        IBar bar = this._barFactory();
    }
}
public interface IBar { }
public class Bar1 : IBar
{
    public Bar1(Pouet p) { }
}
public class Bar2 : IBar
{
}
public class Pouet { }

如果你真的想要在初始解析操作时抛出异常,我可以看到 2 个解决方案:

  1. 创建一个 RegistrationSource,为 Func<T>(或您想要的委托)提供新的实现。不太难,但您必须在初始解析操作期间解析类型。

下面的代码是有关如何执行此操作的示例。我没有使用不同的生命周期注册类型对其进行测试,并且我不知道在某些情况下如何处理这些对象。这段代码应该适用于简单的情况

    /* 
     * This code was not fully tested and it is not optimized
     * It doesn't fully managed the lifetimescope of the object and memory leak may appear
     */
    internal class FixedFactoryRegistrationSource : IRegistrationSource
    {
        internal class FixedFactory<T>
        {
            public FixedFactory(T instance)
            {
                this._instance = instance;
            }

            private readonly T _instance;

            public T GetInstance()
            {
                return this._instance;
            }
        }

        public FixedFactoryRegistrationSource(ContainerBuilder builder)
        {
            builder.RegisterGeneric(typeof(FixedFactory<>)).As(typeof(FixedFactory<>));
        }

        public Boolean IsAdapterForIndividualComponents
        {
            get { return true; }
        }

        public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
                                                                    Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
        {
            IServiceWithType serviceWithType = service as IServiceWithType;
            if (serviceWithType == null || !serviceWithType.ServiceType.IsGenericType)
            {
                yield break;
            }
            if (serviceWithType.ServiceType.GetGenericTypeDefinition() != typeof(Func<>))
            {
                yield break;
            }

            Type elementType = serviceWithType.ServiceType.GetGenericArguments()[0];
            Type fixedFactoryType = typeof(FixedFactory<>).MakeGenericType(elementType);
            Service fixedFactoryService = serviceWithType.ChangeType(fixedFactoryType);

            MethodInfo getInstanceMethod = typeof(FixedFactory<>).MakeGenericType(elementType).GetMethod("GetInstance");
            foreach (IComponentRegistration registration in registrationAccessor(fixedFactoryService))
            {
                yield return RegistrationBuilder.ForDelegate(typeof(Func<>).MakeGenericType(elementType), (c, p) =>
                                                {
                                                    // /!\ disposal of this object is not managed
                                                    Object fixedFactory = c.ResolveComponent(registration, p);
                                                    return getInstanceMethod.CreateDelegate(typeof(Func<>)
                                                                            .MakeGenericType(elementType), fixedFactory);
                                                })
                                                .As(service)
                                                .Targeting(registration)
                                                .CreateRegistration();
            }
        }
    }
  1. 使用模块并浏览依赖关系图。相当困难,您必须完全理解其工作原理 Autofac.

我不建议这样做,因为所有的解决方案都可能非常困难,而且 Autofac 并不是设计成这样工作的。