hadashiA / VContainer

The extra fast, minimum code size, GC-free DI (Dependency Injection) library running on Unity Game Engine.
https://vcontainer.hadashikick.jp
MIT License
2.01k stars 176 forks source link

Strange behavior with ChildLifetimeScope, IEnumerable and Singleton. #697

Closed Akeit0 closed 3 months ago

Akeit0 commented 4 months ago

First, I prepared these classes.

public class A
{
    static int instanceCount = 0;
    readonly int instanceId = instanceCount++;
    public override string ToString()
    {
        return $"A {instanceId}";
    }
}
public class BaseLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.Register<A>(Lifetime.Singleton).AsSelf();
        builder.RegisterBuildCallback(x =>
        {
               Debug.Log("BaseLifetimeScope "+x.Resolve<A>());
        });
    }
}
public class ChildLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.RegisterBuildCallback(resolver =>
        {
            Debug.Log("ChildLifetimeScope "+string.Join(",", resolver.Resolve<IEnumerable<A>>()));
        });
    }
}

Log

BaseLifetimeScope A 0
ChildLifetimeScope A 0

This seems fine.

But, when I changed the ChildLifetimeScope as follows

public class ChildLifetimeScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.Register<A>(Lifetime.Singleton).AsSelf();// I changed this part.

        builder.RegisterBuildCallback(resolver =>
        {
            Debug.Log("ChildLifetimeScope "+string.Join(",", resolver.Resolve<IEnumerable<A>>()));
        });
    }
}

logs changed to

BaseLifetimeScope A 0
ChildLifetimeScope A 1,A 2

. I assumed It would be like ChildLifetimeScope A 1,A 0.

I don't know what the intended behavior is, but I don't think the result is intended.

hadashiA commented 3 months ago

Thanks for the report. it is strange..

📝 Internally, the key of the ConcurrentDictionary holding the Singleton is Registration, but when multiple registrations are found in the parent and child, the keys don't match, so it looks like they are duplicate instantiated.

hadashiA commented 3 months ago

Fixed in #698 .

Now the behavior is as follows.