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

时间:2015-04-15 13:14:48

标签: c# autofac

在解析服务时,使用自动生成的工厂与否之间存在差异。例如,如果我有这些类:

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>()将返回一个委托,该委托将在调用时抛出DependencyResolutionException

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

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

1 个答案:

答案 0 :(得分:1)

  

在我看来,c.Resolve()提供的行为更可取,因为在解析服务时会抛出异常

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

请看以下示例:

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>(或您想要的代理人)提供新的实施。不太困难,但您必须在初始解析操作期间解决该类型。
  2. 下面的代码是如何做到这一点的示例。我没有用不同的生命周期注册类型测试它,我也不知道这些对象的处理在某些情况下是如何工作的。此代码适用于简单的情况

        /* 
         * 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
    2. 我不推荐这样做,因为所有解决方案都非常困难,并且 Autofac 的设计并非如此。