Sorry I couldn't get back sooner, been swamped all week.  Okay here is what 
i mean.  I've attached the full CS file so you can verify 

But here is the breakdown for reference
Here are the subjects and their dependencies:
        public interface IA
        {
            IB B {get;}
        }
        public class A : IA
        {
            public IB B {get; private set; }
            public A(IB b) { B = b; }
        }

        public interface IB
        {
            IEnumerable<IC> Cs { get; }
        }
        public class B : IB
        {
            public IEnumerable<IC> Cs {get; private set; }
            public B(IEnumerable<IC> cs) { Cs = cs; }
        }

        public interface IC{}
        public class C1 : IC
        {
            public C1() {}
        }
        public class C2 : IC
        {
            public IA A { get; private set; }
            public C2(IA a) { A = a; }
        }
Clearly C2 has a circular dependency but C1 does not.

Here is the test that represents the behaviour that I would like to see

        [Test]
        public void CastleCircularTest() 
        {
            var container = new WindsorContainer();
            container.AddFacility<TypedFactoryFacility>();
            container.Kernel.Resolver.AddSubResolver(new 
CollectionResolver(container.Kernel, true));
            
container.Register(AllTypes.FromThisAssembly().Pick().WithServiceAllInterfaces().WithServiceBase());

            var resolvedA = container.Resolve<IA>();
            Assert.That(resolvedA, Is.Not.Null);
            Assert.That(resolvedA.B.Cs.Count(), Is.EqualTo(1));
            Assert.That(resolvedA.B.Cs.Single().GetType(), 
Is.EqualTo(typeof(C1)));
        }

The test (obviously) does not pass.  When trying to Resolv IA, I get the 
following exception (to recreate this behaviuor, just flip the commented 
out lines:
Dependency cycle has been detected when trying to resolve component 
'CastleCoreTests.CastleCircularTestFixture+A'.
The resolution tree that resulted in the cycle is the following:
Component 'CastleCoreTests.CastleCircularTestFixture+A' resolved as 
dependency of
component 'CastleCoreTests.CastleCircularTestFixture+C2' resolved as 
dependency of
component 'CastleCoreTests.CastleCircularTestFixture+B' resolved as 
dependency of
component 'CastleCoreTests.CastleCircularTestFixture+A' which is the root 
component being resolved.

Okay, so to solve this, I introduce a CustomCollectionResolver, and 
register it on the container instead of the CollectionResolver
Registration:
container.Kernel.Resolver.AddSubResolver(new 
CustomCollectionResolver(container.Kernel));

The Resolver:
    public class CustomCollectionResolver : CollectionResolver
    {
        private readonly IKernel _kernel;

        public CustomCollectionResolver(IKernel kernel)
            : base(kernel, true) { _kernel = kernel; }

        public override object 
Resolve(Castle.MicroKernel.Context.CreationContext context, 
ISubDependencyResolver contextHandlerResolver, Castle.Core.ComponentModel 
model, Castle.Core.DependencyModel dependency)
        {
            var resolved = new List<object>();

            var handlers = 
_kernel.GetHandlers(GetItemType(dependency.TargetItemType));
            foreach (var handler in handlers)
            {
                try
                {
                    resolved.Add(handler.Resolve(context));
                }
                catch (CircularDependencyException)
                {
                    //Ignore circular dependencies
                }
            }

            return resolved;
        }
    }

This just leads to {"ComponentActivator: could not instantiate 
CastleCoreTests.CastleCircularTestFixture+B"}
{"Object of type 'System.Collections.Generic.List`1[System.Object]' cannot 
be converted to type 
'System.Collections.Generic.IEnumerable`1[CastleCoreTests.CastleCircularTestFixture+IC]'."}

On Thursday, 18 April 2013 17:17:09 UTC-7, Krzysztof Koźmic wrote:
>
> Nik,
>
> actually I think this should be working out of the box.
>
> Can you please build a simple test reproducing the behavior...
>
> I think I may be missing something here
>
>
> On 18 April 2013 16:15, Nik Pinski <npi...@gmail.com <javascript:>> wrote:
>
>> Creating a custom Collection Resolver sounds promising.
>>
>> So I see that the existing logic for detecting cycles is in 
>> DefaultHandler.  IsBeingResolvedInContext uses the CreationContext to find 
>> out context.IsInResolutionContext(this); which tells it if the handler is 
>> already being resolved in the context.
>>
>> Makes sense.  But in the context of a SubDependencyResolver that I would 
>> be writing (or overriding CollectionResolver), how do i get at the handler? 
>>  I think I don't understand enough about what step in the resolution 
>> lifecycle the subdependencyresolver is invoked...
>>
>>
>> On Wednesday, 17 April 2013 22:21:51 UTC-7, Krzysztof Koźmic wrote:
>>
>>>  so I think what you want is a custom Collection resolver that checks 
>>> if a IHandler is already in the graph and then ignores it. There's a method 
>>> on ResolutionContext or similar that does that 
>>>
>>>
>>> HTH
>>> -- 
>>> Krzysztof Kozmic
>>>
>>> On Wednesday, 17 April 2013 at 3:26 PM, Nik Pinski wrote:
>>>
>>> I have a generic repository (the generic type parameter being the 
>>> aggregate root type being serialized to the database [mongo]).
>>>
>>> The repository takes a parameter which in an IEnumerable of ISync 
>>> services.  Low-level database actions may need to be synchronized to other 
>>> data, and implementors of ISync will do that.
>>>
>>> Some psudeocode:
>>>
>>> class Repository<T>
>>> {
>>>     public Repository(IEnumerable<ISync<**T>> synchronizers)
>>>     {
>>>     ...
>>>     }
>>>
>>>     public void Save(T data)
>>>     {
>>>         database.Save(data);
>>>         foreach(synchronizer in _syncrhonizers)
>>>         {
>>>             synchronizer.Sync(data);
>>>         }
>>>     }
>>> }
>>>
>>> class SomeRandomSync : ISync<ObjectA>
>>> {
>>>     public void Sync(ObjectAdata)
>>>     {
>>>         //do something with that object perhaps even use another 
>>> repository
>>>         new Repository<ObjectB>().Save(**objectB); //Obviously this is 
>>> a constructor injection, I'm just keeping it simple
>>>     }
>>> }
>>>
>>> Most objects don't have an ISync<T> implementation, so the synchronizers 
>>> do nothing.  
>>>
>>> However whenever dealing with such low level injected dependencies there 
>>> can easily be a dependency cyle.  What if there is an implementation of 
>>> ISync<ObjectB> that, when syncing ObjectBdecides to Save ObjectA?  Well, an 
>>> infinite loop of saves and re-saves that LUCKILY, Castle Windsor would 
>>> identify ahead of time and tell you "Hey, you've got a dependency cycle and 
>>> you're doing something wrong."
>>>
>>> Luckily only 99% of the time, though, because in my case i don't WANT it 
>>> to cause a cyclical dependency, I just want that particular ISync<T> 
>>> service to be ignored.  I want to allow the developers using this code to 
>>> be able to create those dependency cycles (sometimes they are quite 
>>> necessary because SOME implementors of ISync need to be called, and some 
>>> should just be ignored if they can't be - they will surely not cause a 
>>> cycle in another situation.
>>>
>>> I tried to do something like this but to no avail 
>>> (StackOverflowException).  Do I have any recourse?
>>>
>>>         public Repository(IWindsorContainer windsorContainer)
>>>         {
>>>             var handlers = windsorContainer.Kernel.**
>>> GetHandlers(typeof(ISync<T>));
>>>
>>>             var syncers = new List<object>();
>>>             foreach (var handler in handlers)
>>>             {
>>>                 try
>>>                 {
>>>                     object syncer= handler.TryResolve(**
>>> CreationContext.CreateEmpty())**;
>>>                     syncers.Add(syncer);
>>>                 }
>>>                 catch
>>>                 {
>>>                 }
>>>             }
>>>
>>>             _syncers = syncers;
>>>         }
>>>  
>>> -- 
>>> You received this message because you are subscribed to the Google 
>>> Groups "Castle Project Users" group.
>>> To unsubscribe from this group and stop receiving emails from it, send 
>>> an email to castle-project-users+**unsubscr...@googlegroups.com.
>>> To post to this group, send email to castle-pro...@**googlegroups.com.
>>>
>>> Visit this group at http://groups.google.com/**
>>> group/castle-project-users?hl=**en<http://groups.google.com/group/castle-project-users?hl=en>
>>> .
>>> For more options, visit 
>>> https://groups.google.com/**groups/opt_out<https://groups.google.com/groups/opt_out>
>>> .
>>>  
>>>  
>>>  
>>>  
>>>   -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Castle Project Users" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to castle-project-users+unsubscr...@googlegroups.com <javascript:>.
>> To post to this group, send email to 
>> castle-pro...@googlegroups.com<javascript:>
>> .
>> Visit this group at 
>> http://groups.google.com/group/castle-project-users?hl=en.
>> For more options, visit https://groups.google.com/groups/opt_out.
>>  
>>  
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Castle Project Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to castle-project-users+unsubscr...@googlegroups.com.
To post to this group, send email to castle-project-users@googlegroups.com.
Visit this group at http://groups.google.com/group/castle-project-users?hl=en.
For more options, visit https://groups.google.com/groups/opt_out.


?using System.Collections.Generic;
using Castle.Facilities.TypedFactory;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.Resolvers.SpecializedResolvers;
using Castle.Windsor;
using NUnit.Framework;
using System.Linq;

namespace CastleCoreTests
{
    [TestFixture]
    public class CastleCircularTestFixture
    {
        public interface IA
        {
            IB B {get;}
        }
        public class A : IA
        {
            public IB B {get; private set; }
            public A(IB b) { B = b; }
        }

        public interface IB
        {
            IEnumerable<IC> Cs { get; }
        }
        public class B : IB
        {
            public IEnumerable<IC> Cs {get; private set; }
            public B(IEnumerable<IC> cs) { Cs = cs; }
        }

        public interface IC{}
        public class C1 : IC
        {
            public C1() {}
        }
        public class C2 : IC
        {
            public IA A { get; private set; }
            public C2(IA a) { A = a; }
        }


        [Test]
        public void CastleCircularTest() 
        {
            var container = new WindsorContainer();
            container.AddFacility<TypedFactoryFacility>();

            //The two sub-resolvers
//            container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, true));
            container.Kernel.Resolver.AddSubResolver(new CustomCollectionResolver(container.Kernel));

            container.Register(AllTypes.FromThisAssembly().Pick().WithServiceAllInterfaces().WithServiceBase());

            var resolvedA = container.Resolve<IA>();
            Assert.That(resolvedA, Is.Not.Null);
            Assert.That(resolvedA.B.Cs.Count(), Is.EqualTo(1));
            Assert.That(resolvedA.B.Cs.Single().GetType(), Is.EqualTo(typeof(C1)));
        }
    }

    public class CustomCollectionResolver : CollectionResolver
    {
        private readonly IKernel _kernel;

        public CustomCollectionResolver(IKernel kernel)
            : base(kernel, true) { _kernel = kernel; }

        public override object Resolve(Castle.MicroKernel.Context.CreationContext context, ISubDependencyResolver contextHandlerResolver, Castle.Core.ComponentModel model, Castle.Core.DependencyModel dependency)
        {
            var resolved = new List<object>();

            var handlers = _kernel.GetHandlers(GetItemType(dependency.TargetItemType));
            foreach (var handler in handlers)
            {
                try
                {
                    resolved.Add(handler.Resolve(context));
                }
                catch (CircularDependencyException)
                {
                    //Ignore circular dependencies
                }
            }

            return resolved;
        }
    }


}

Reply via email to