gpt4 book ai didi

c# - 注册装饰器与注册 IEnumerable 冲突

转载 作者:太空宇宙 更新时间:2023-11-03 10:57:31 26 4
gpt4 key购买 nike

我正在使用 simpleinjector 2.3.0.0 和 .net 4.5。

我一直在尝试注册一个依赖于 IEnumerable 的工厂、一个事物的实例以及一个工作单元装饰器。 (除其他事项外)

这是我的工厂:

public class ThingFactory : IThingFactory
{
private readonly IEnumerable<IThing> things;

public ThingFactory (IEnumerable<IThing> things)
{
this.things= things;
}

public IThing GetThing(ThingType thingType)
{
return things.FirstOrDefault(t => t.IsApplicable(thingType));
}
}

这是我对 IThing 的实现

 public class ThingOne: IThing
{
private IThingFactory thingFactory;

public ThingOne(IThingFactory thingFactory)
{
this.thingFactory= thingFactory;
}

public void Execute(MyDto myDto)
{
//do stuff
//get the next approiate IThing out of the factory and execute
}

public bool IsApplicable(ThingType thingType)
{
return thingType == ThingType.ThingOne;
}

我的注册是

  container.RegisterAll<IThing>(
from tp in typeof (IThing).Assembly.GetExportedTypes()
where !tp.IsAbstract
where typeof (IThing).IsAssignableFrom(tp)
select tp);

container.Register<IThingFactory , ThingFactory>();

这绝对没问题,我可以无一异常(exception)地验证容器。但是,当我还将以下注册添加到容器时,出现异常

 container.RegisterDecorator(typeof(ICommandHandler<,>),    
typeof(UnitOfWorkDecorator<,>));

装饰器是一个 Nhibernate UnitOFWork,它管理一个 Nhibernate 事务(这并不重要)(遵循此模式 https://cuttingedge.it/blogs/steven/pivot/entry.php?id=91)

  public class UnitOfWorkDecorator<TCommand, TResult>
: ICommandHandler<TCommand, TResult>
where TCommand : ICommand
{

public UnitOfWorkDecorator(
ICommandHandler<TCommand, TResult> decoratedCommandHandler)
{
this.currentSessionContextService = currentSessionContextService;
this.decoratedCommandHandler = decoratedCommandHandler;
}

public void Handle(TCommand command)
{
//start my nhibernate transaction
decoratedCommandHandler.Handle(command);

//commit the transaction
}

所以无论如何,当我添加装饰器时,我得到以下异常。当我打电话时

  container.Verify();

然而,当我删除装饰器注册时,一切又好了。

Topshelf v3.1.107.0, .NET Framework v4.0.30319.18052
Topshelf.Hosts.ConsoleRunHost Error: 0 : An exception occurred, System.Reflectio
n.TargetInvocationException: Exception has been thrown by the target of an invoc
ation. ---> System.InvalidOperationException: The configuration is invalid. Crea
ting the instance for type IThingManager failed. The registered delegate for t
ype IThingManager threw an exception. The registered delegate for type IThingFa
ctory threw an exception. The registered delegate for type IEnumerable<IThing> th
rew an exception. No registration for type ThingOne could be found a
nd an implicit registration could not be made. ---> SimpleInjector.ActivationEx
ception: The registered delegate for type IThingManager threw an exception. Th
e registered delegate for type IThingFactory threw an exception. The registered d
elegate for type IEnumerable<IThing> threw an exception. No registration for type
ThingOne could be found and an implicit registration could not be m
ade. ---> SimpleInjector.ActivationException: The registered delegate for type
IThingFactory threw an exception. The registered delegate for type IEnumerable<IThing>
threw an exception. No registration for type ThingOne could be
found and an implicit registration could not be made. ---> SimpleInjector.Activ
ationException: The registered delegate for type IEnumerable<IThing> threw an exc
eption. No registration for type ThingOne could be found and an impl
icit registration could not be made. ---> SimpleInjector.ActivationException: N
o registration for type ThingOne could be found and an implicit regi
stration could not be made.

堆栈跟踪:

at SimpleInjector.Container.ThrowNotConstructableException(Type concreteType)
at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type servic
eType)at SimpleInjector.Container.GetRegistration(Type serviceType, Boolean throwOn
Failure) at SimpleInjector.Advanced.ContainerControlledCollection`1.
<>c__DisplayClass1
0.<ToLazyInstanceProducer>b__f() at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue() at
SimpleInjector.Advanced.ContainerControlledCollection`1.<SimpleInjector.Ad
vanced.IContainerControlledCollection.GetRelationships>b__1(Lazy`1 p)
at System.Linq.Enumerable.WhereSelectListIterator`2.MoveNext()
at System.Linq.Enumerable.<SelectManyIterator>d__31`3.MoveNext()
at System.Linq.Enumerable.<DistinctIterator>d__81`1.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at SimpleInjector.Advanced.ContainerControlledCollection`1.SimpleInjector.Adv
anced.IContainerControlledCollection.GetRelationships()
at SimpleInjector.Extensions.Decorators.DecoratorHelpers.ContainerControlledC
ollectionRegistration.GetRelationshipsCore()
at SimpleInjector.Registration.GetRelationships()
at SimpleInjector.InstanceProducer.GetRelationships()
at SimpleInjector.Container.OnExpressionBuilt(ExpressionBuiltEventArgs e, Ins
tanceProducer instanceProducer)
at SimpleInjector.InstanceProducer.BuildExpressionInternal()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at SimpleInjector.InstanceProducer.BuildExpression()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.BuildExpression()
at SimpleInjector.Advanced.DefaultConstructorInjectionBehavior.BuildParameter
Expression(ParameterInfo parameter)
at SimpleInjector.Registration.BuildParameterExpressionFor(ParameterInfo para
meter)
at SimpleInjector.Registration.<BuildNewExpression>b__1a(<>f__AnonymousTypef`
2 <>h__TransparentIdentifier18)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at SimpleInjector.Registration.BuildNewExpression(Type serviceType, Type impl
ementationType)
at SimpleInjector.Registration.BuildTransientExpression[TService,TImplementat
ion]()
at SimpleInjector.Lifestyles.TransientLifestyle.TransientLifestyleRegistratio
n`2.BuildExpression()
at SimpleInjector.InstanceProducer.BuildExpressionInternal()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at SimpleInjector.InstanceProducer.BuildExpression()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.BuildExpression()
at SimpleInjector.Advanced.DefaultConstructorInjectionBehavior.BuildParameter
Expression(ParameterInfo parameter)
at SimpleInjector.Registration.BuildParameterExpressionFor(ParameterInfo para
meter)
at SimpleInjector.Registration.<BuildNewExpression>b__1a(<>f__AnonymousTypef`
2 <>h__TransparentIdentifier18)
at System.Linq.Enumerable.WhereSelectArrayIterator`2.MoveNext()
at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
at SimpleInjector.Registration.BuildNewExpression(Type serviceType, Type impl
ementationType)
at SimpleInjector.Registration.BuildTransientExpression[TService,TImplementat
ion]()
at SimpleInjector.Lifestyles.TransientLifestyle.TransientLifestyleRegistratio
n`2.BuildExpression()
at SimpleInjector.InstanceProducer.BuildExpressionInternal()
at System.Lazy`1.CreateValue()
at System.Lazy`1.LazyInitValue()
at SimpleInjector.InstanceProducer.BuildInstanceCreator(Object& createdInstan
ce)
at SimpleInjector.InstanceProducer.GetInstance()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.InstanceProducer.Verify()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.Verify()
at SimpleInjector.Container.VerifyProducers(InstanceProducer[] producersToVer
ify)
at SimpleInjector.Container.ValidateRegistrations()
at SimpleInjector.Container.Verify()

谢谢你的帮助

编辑 - ThingManager 是入口点,如下所示:

   public class ThingManager : IThingManager
{
private readonly IThingFactory thingFactory;

public ThingManager(IThingFactory thingFactory)
{
this.thingFactory = thingFactory;
}

public void Run(MyDto myDto)
{
var firstThing = thingFactory.GetThing(ThingType.ThingOne);
firstThing.Execute(myDto);
}
}

最佳答案

问题是由您的代码中的循环引用引起的:ThingFactory取决于 IEnumerable<IThing> , 这取决于 ThingOne , 这取决于 ThingFactory ,这将关闭循环。

不幸的是由于 a bug在 Simple Injector 2.3 中,描述循环引用的真正错误被隐藏,并抛出一条表达能力较差(在本例中甚至不正确)的消息。此错误已在 Simple Injector 2.3.5 中得到修复.

尽管循环引用存在于您的代码库中,Verify方法仅在注册装饰器时注意到此错误。内部ContainerControlledCollection<T>导致注册的元素被预编译,这允许 InstanceProducer注意循环的实例。没有 ContainerControlledCollection<T>即使在解析类型时,集合的评估也更加延迟,这完全隐藏了这个错误。然而,您设计中的这个怪癖可能仍然会在以后引起各种问题。

对于即将推出的 Simple Injector 2.4 ContainerControlledCollection<T>Verify() 的情况下实际上会更懒惰地提高性能不被调用(这对于具有深层对象图和包含许多项的集合的应用程序有意义),但这意味着即使使用装饰器,验证器也不会抛出异常。

Simple Injector 2.4 不抛出异常的行为其实是正确的(事实上 2.3 和 2.3.5 抛出异常可以被认为是一个错误),因为 Simple Injector 的目标是在构建对象时防止 stackoverflow 异常图(当调用 GetInstance 时)。由于 IEnumerable<T> 之后类型的创建被延迟使用(解析 IEnumerable<T> 不解析实例;只有迭代集合才解析),没有 stackoverflow 异常。

虽然在您的代码中使用循环引用可能会产生代码异味,但在您的代码中它可能只会导致代码中的递归(但不会导致 stackoverflow),这可能是预期的行为。

您仍然可能想要重新考虑设计,因为递归深度为 10(假设您有 10 个东西并调用工厂以获取列表中的下一个东西),这将触发创建 55 个东西(10 倍于第一个元素,9 个第二个元素,8 个第三个,... 1 个第十个元素),这可能不是您所期望的。

关于c# - 注册装饰器与注册 IEnumerable<T> 冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18916981/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com