ipjohnson / Grace

Grace is a feature rich dependency injection container library
MIT License
336 stars 33 forks source link

RecursiveLocateException with factory injection #307

Open mythteria opened 1 year ago

mythteria commented 1 year ago

Hi! I am migrating from autofac to grace ioc and ran into an issue. Suppose such a structure (simplified):

class AService
{
    private readonly Func<ADependency> _func;

    public AService(Func<ADependency> func) =>
        _func = func;

    public ADependency GetDependency() =>
        _func();
}

class ADependency
{
    public ADependency(AService a)
    {
    }
}

Autofac registration works fine:

var autofacContainerBuilder = new ContainerBuilder();
autofacContainerBuilder.RegisterType<ADependency>();
autofacContainerBuilder.RegisterType<AService>();
var autofacContainer = autofacContainerBuilder.Build();
var s1 = autofacContainer.Resolve<AService>();

Unfortunately, when i port it to grace, i got a RecursiveLocateException:

var graceContainer = new DependencyInjectionContainer();
graceContainer.Configure(c =>
{
    c.Export<ADependency>();
    c.Export<AService>(); // throws!
    // c.ExportFactory<IExportLocatorScope, AService>(scope => new AService(scope.Locate<Func<ADependency>>())); // work
});
var s2 = graceContainer.Locate<AService>();

I found a workaround (commented), but it looks rather ugly. Is there a more elegant way to solve this problem?

Lex45x commented 10 months ago

Hi! I hope this issue is still relevant.

From the example you've provided, it seems like Grace is trying to build a dependency graph based on the constructor parameters but it encounters circular dependencies. Autofac works in a completely different way under the hood and so you are not facing this kind of problem with it. Workaround is functioning because you are giving direct instructions on how the AService factory should work. So, Grace is not trying to build it for you.

If you can provide a more detailed explanation of the behavior you want to achieve I could help you to get around it.

Do you need any of those services to be a singleton? Or do you expect Each call to GetDependency to create new instances of ADependency together with AService?