JasperFx / lamar

Fast Inversion of Control Tool and Successor to StructureMap
https://jasperfx.github.io/lamar
MIT License
566 stars 117 forks source link

Registering two named types with same name does not override first type #224

Open rchamorro opened 4 years ago

rchamorro commented 4 years ago

When registering two named instances with the same name, or the same registry is registered multiple times, Lamar is not able to find the named instance.

It throws this exception:

Lamar.IoC.LamarMissingRegistrationException Unknown service registration 'A'

I would expect that if the name matches, the type is overriden by the last registered. Instead it creates two named instances "A1" and "A2"

This is the test I used:

[Fact]
public void Should_be_overwritten()
{
    var container = Container.For(_ =>
    {
        _.For<IWidget>().Use<Widget1>().Named("A");
        _.For<IWidget>().Use<Widget2>().Named("A");
    });

    container.GetInstance<IWidget>("A").ShouldNotBeOfType<Widget2>();
}

I found the "problem" because I have a complex solution where I try to have a registry for each project and include the registry when there are dependencies between them. That makes that some registries are included multiple times.

jeremydmiller commented 4 years ago

@rchamorro I'm not going to tackle this in 4.1 because we need to talk about how this should actually work. The "makeNamesUnique()" step is important for other reasons. Are these really different registrations with the same name? Do you control the order in which they're registered?

You could simply add an extension method that would replace a named instance or remove a named instance. ServiceRegistry is really just a List<ServiceDescriptor>. If you're registering services via Lamar, the ServiceDescriptor.ImplementationInstance is the Lamar Instance.

There's a workaround for what you need to do that doesn't involve code changes, so I'm going to leave this out for now.

rchamorro commented 4 years ago

There are no different registrations with the same name but the same registry is included in other registries multiple times just to make sure that they have all the required dependencies.

jeremydmiller commented 4 years ago

@rchamorro Sorry, catching up on Lamar for the first time in forever. In the case you're describing, it wouldn't be hard to just remove the prior registrations or to use an AddIfMissing kind of extension as a work around.

darman96 commented 2 years ago

Having the same problem. My use case is that I want certain services to be overridden in UnitTests.

Shouldn't this behave just like normal registrations where the last registered service is considered default?

For<IService>.Use<Service1>()
For<IService>.Use<Service2>()
// --> Service2 used as default

For<IService>.Use<Service1>().Named("SomeService")
For<IService>.Use<Service2>().Named("SomeService")
// --> Service2 used as default

This would at least be better than just assigning the service some "random" name especially since this is not documented.