ipjohnson / Grace

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

Export factory to generics #139

Closed mcdis closed 6 years ago

mcdis commented 6 years ago

Hi! How I can configure export factory to a generics type? I want to bind ISomeGenericsInterface<T> to factory Func<T> method (single instance in container)

ipjohnson commented 6 years ago

@mcdis I'm not sure I completely follow can you post some examples of what you want to do?

mcdis commented 6 years ago
container.Configure(_=>_.ExportFactory(typeof(ISomeGenericsInterface<>),_type=>FactoryMethod(_type)).Lifcycle.Singleton());

var a = container.Locate<ISomeGenericsInterface<MyResource>>();
// a = FactoryMethod(typeof(ISomeGenericsInterface<MyResource>));
var b = container.Locate<ISomeGenericsInterface<MyResource>>();
// b = a (singleton)
var isEq = object.ReferenceEquals(a,b); //isEq = true

In my case I know how to locate ISomeGenericsInterface and the result have to be singleton. But I don't know concrete types. So When ISomeGenericsInterface locate the factory method have to be called and the result must cached (Singletone).

mcdis commented 6 years ago

Another words, I need a way to define factory which locate generic interface ISomeInterface<T>

ipjohnson commented 6 years ago

Hi @mcdis

There isn't anything specifically built in to do that but I believe you could get the behavior you are looking for using IMissingExportStrategyProvider. I'll see about writing something up this evening.

ipjohnson commented 6 years ago

@mcdis sorry took me a bit but here is the final implementation.

ipjohnson commented 6 years ago

@mcdis can I go a head and close this as completed?

Adanaran commented 6 years ago

Hi @ipjohnson I have used your proposal above to create generic types through a method. This works as expected, apart from when a type bound with this strategy is injected into another type. This can be solved by wrapping the created expression with a cast before returning it in line 146. Code added:

expression = Expression.Convert(expression, activationType);

Test case:

public class Outer
{
    public ITestGenericService<int> IntService { get; }

    public Outer(ITestGenericService<int> intService)
    {
        IntService = intService;
    }
}

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

    container.Configure(c => c.AddActivationStrategy(new GenericFatoryExportStrategy(container,
        typeof(ITestGenericService<>), FactoryMethod)));

    var outer = container.Locate<Outer>();
    Assert.NotNull(outer);
    Assert.IsType<Outer>(outer);
    Assert.NotNull(outer.IntService);
    Assert.IsType<Impl1>(outer.IntService);
}
mcdis commented 6 years ago

Hi @ipjohnson good job. Yes, you can close and go ahead