ipjohnson / Grace

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

Multiple constructors - how to specify which one to use? #258

Closed bangiev closed 4 years ago

bangiev commented 4 years ago

Hello and thank you for you efforts in developing and maintaining Grace! We've selected it as a candidate for replacing Ninject in our team project and I stumbled upon the following scenario which surprised me:

I have a setup in which there is a generic type with multiple constructors. I decorated the parameterless constructor with the [Import] attribute and expected that Grace would select that one which did not happen. You can see the test I wrote for the scenario:

public class Dependency { }

public class Service<T>
{
    [Import]
    public Service()
    {
        ParameterlessConstructorCalled = true;
    }

    public Service(T value)
    {
        Value = value;
    }

    public bool ParameterlessConstructorCalled { get; }
    public T Value { get; }
}

[Fact]
public void MultipleConstructors_DecorateSpecificConstructorWithImport_DecoratedConstructorUsed()
{
    var container = new DependencyInjectionContainer();

    var service = container.Locate<Service<Dependency>>();

    Assert.True(service.ParameterlessConstructorCalled);
}

Is that not how the Import attribute is supposed to work? Or how would you suggest to achieve that explicit constructor selection?

I tried adding the following configuration to the container as well but that didn't work either:

container.Configure(c => c
    .Export(typeof(Service<>))
    .ImportConstructor(typeof(Service<>).GetConstructor(Type.EmptyTypes)));

I guess I could make this work by excluding the Dependency type from auto registration but I wouldn't go that way due to the multiple types that are potentially passed to the generic.

ipjohnson commented 4 years ago

Hi @bangiev

Currently the ImportAttribute isn't considered on constructors but I think that's a reasonable feature request. I'm releasing 7.1.1 tomorrow but I think I can push out a beta with this feature on Sunday.

silkfire commented 4 years ago

What is the [Import] attribute used for? Couldn't find anything about this in the documentation :)

ipjohnson commented 4 years ago

Importing properties and methods but it does seem like it would make sense as a constructor selector

silkfire commented 4 years ago

So without exporting a class, I can import its method and properties? How do I then invoke that method?

ipjohnson commented 4 years ago

No more like when exporting a class you can mark a property or method for import and it will be treated as a dependency and injected on construction (for methods the instance is created and then the method called with dependencies). It used to be a very popular way of doing dependencies but now constructor injection is more in vogue.

bangiev commented 4 years ago

Sounds great, thanks @ipjohnson. I'll keep an eye on the nuget feed.

ipjohnson commented 4 years ago

I've checked in changes for this issue and there is a build in the CI feed. Would you be able to test that before I push a release?

CI Feed
https://ci.appveyor.com/nuget/grace-master
bangiev commented 4 years ago

Great, I will test that probably today or tomorrow and will let you know how it went.

bangiev commented 4 years ago

I tested the 7.2.0-Beta799 version this morning and this feature seems to work perfect @ipjohnson. Thank you for implementing that :) What are your plans on pushing a 7.2.0 version? (not familiar with Grace's release life cycle)

ipjohnson commented 4 years ago

I'll do a release in the next couple days and comment here when I do it

ipjohnson commented 4 years ago

Ok I've pushed a new beta version to NuGet with this feature

bangiev commented 4 years ago

Thank you!