有什么办法可以更快地解决依赖关系?
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 个解决方案:
- 创建一个
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();
}
}
}
- 使用模块并浏览依赖关系图。相当困难,您必须完全理解其工作原理 Autofac.
我不建议这样做,因为所有的解决方案都可能非常困难,而且 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>()
将 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 个解决方案:
- 创建一个
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();
}
}
}
- 使用模块并浏览依赖关系图。相当困难,您必须完全理解其工作原理 Autofac.
我不建议这样做,因为所有的解决方案都可能非常困难,而且 Autofac 并不是设计成这样工作的。