C# 注册装饰程序与注册IEnumerable冲突<;T>;

C# 注册装饰程序与注册IEnumerable冲突<;T>;,c#,.net,dependency-injection,simple-injector,C#,.net,Dependency Injection,Simple Injector,我正在使用simpleinjector 2.3.0.0和.net 4.5 我一直在尝试注册一个依赖于IEnumerable的工厂,一个对象的实例,外加一个unitofwork装饰器。(除其他事项外) 这是我的工厂: public class ThingFactory : IThingFactory { private readonly IEnumerable<IThing> things; public ThingFactory (IEnumerable<IT

我正在使用simpleinjector 2.3.0.0和.net 4.5

我一直在尝试注册一个依赖于IEnumerable的工厂,一个对象的实例,外加一个unitofwork装饰器。(除其他事项外)

这是我的工厂:

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

我的注册号是

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

   container.Register<IThingFactory , ThingFactory>();
然而,当我取消装饰注册时,一切又恢复了正常

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.

问题是由代码中的循环引用引起的:
ThingFactory
依赖于
IEnumerable
,它依赖于
ThingOne
,后者依赖于关闭循环的
ThingFactory

不幸的是,在Simple Injector 2.3中,描述循环引用的实际错误被隐藏,并且抛出了一条表达性较差(在本例中甚至不正确)的消息。这个错误被修复了

尽管循环引用存在于代码库中,但是
Verify
方法仅在注册装饰程序时才注意到此错误。内部
ContainerControlledCollection
会导致预编译已注册的元素,从而允许
InstanceProducer
实例注意到循环。如果没有
ContainerControlledCollection
,则会更缓慢地计算集合,从而完全隐藏此错误,即使在解析类型时也是如此。然而,您的设计中的这一怪癖可能会在以后引起各种各样的麻烦

对于即将推出的Simple Injector 2.4,
ContainerControlled Collection
实际上将在未调用
Verify()
的情况下更为迟缓地执行操作,以提高性能(这对于具有深层对象图的应用程序和具有许多项的集合是有意义的),但这意味着即使使用装饰器,验证器也不会抛出异常

Simple Injector 2.4不抛出异常的行为实际上是正确的(2.3和2.3.5抛出异常的事实可以被认为是一个bug),因为Simple Injector的目标是在构建对象图时(调用
GetInstance
时)防止堆栈溢出异常。由于由于使用了
IEnumerable
(解析
IEnumerable
不会解析实例;只有迭代集合才会解析实例),因此不存在stackoverflow异常

尽管在代码中使用循环引用可能是一种代码气味,但在代码中它可能只会导致代码中的递归(但不会导致堆栈溢出),这可能是预期的行为


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

错误的大小写很奇怪(请看
TH
),也许这就是问题所在(尽管我在您的代码中没有找到它)<代码>找不到**THingOne类型的注册,无法进行隐式注册。发现得很好。我实际上已经改变了他们的真实姓名。现在已更新错误。能否显示
ThingManager
实现?刚刚在底部添加了ThingManager。
ThingOne
ThingFactory
正在间接引用彼此。由于
ThingOne
的创建被延迟,因为它位于
IEnumerable
中,但这仍然是个坏主意。谢谢,我将删除产品中的工厂注入。
 container.RegisterDecorator(typeof(ICommandHandler<,>),    
 typeof(UnitOfWorkDecorator<,>));
  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()
   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);
    }
}