Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request: Add a IContainerBuilder.RegisterProvider method #205

Closed
schultzcole opened this issue Apr 30, 2021 · 3 comments
Closed

Request: Add a IContainerBuilder.RegisterProvider method #205

schultzcole opened this issue Apr 30, 2021 · 3 comments

Comments

@schultzcole
Copy link

I would like a way to more easily delegate resolving a type to another function or class. Here's my thoughts for a few new RegisterProvider methods. The idea is that when resolving a given type T, it would invoke the provider and inject the returned result. Unlike a Factory, a provider would be called at the time of resolution, whereas a factory is injected directly.

public static RegistrationBuilder RegisterProvider<T>(this IContainerBuilder builder, Func<T> provider) { }
public static RegistrationBuilder RegisterProvider<TParam1, T>(this IContainerBuilder builder, Func<TParam1, T> provider) { }
public static RegistrationBuilder RegisterProvider<T>(this IContainerBuilder builder, Func<IObjectResolver, T> provider) { }
public static RegistrationBuilder RegisterProvider<T>(this IContainerBuilder builder, IProvider<T> provider) { }

Here's a simple example of how it would be used

Container:

protected override void Configure(IContainerBuilder builder)
{
    // Example 1: Super basic, basically equivalent to Lifetime.Transient but worse
    builder.RegisterProvider(() => new Foo());

    // Example 2:
    builder.Register<IMyService, MyServiceImpl>();
    // Delegating resolution of `Foo` to `IMyService`
    builder.RegisterProvider<IMyService, Foo>(myService => myService.ProvideFoo());
    // Or
    builder.RegisterProvider<Foo>(resolver => resolver.Resolve<IMyService>().ProvideFoo());
}

Consumer:

public class Bar
{
    // `Foo` is provided by provider specified above
    public Bar(Foo myFoo)
    {
        myFoo.DoThing();
    }
}

Maybe there is already a way of doing this sort of thing, but I haven't been able to find a good way to do it.

@schultzcole schultzcole changed the title Request: Add a IContainerBuilder.RegisterResolver method Request: Add a IContainerBuilder.RegisterProvider method Apr 30, 2021
@hadashiA
Copy link
Owner

hadashiA commented May 1, 2021

Agree.

Microsoft.Extensions.DependencyInjection and others also support this, and I think it is useful.

As for the name of the method you suggested, what "*Provider" means is not so obvious to me, so Im thinking of the following signature.

builder.Register<IFoo>(_ => new Foo(), Lifetime.Scoped);

--

In Unity, I think there is a risk that capturing to lambda expressions could cause problems with objects having unintended lifetimes, but oh well, I won't worry about it.

@schultzcole
Copy link
Author

I have another request that is related to this issue. It would be nice if you could use a similar delegate style with the WithParameter method, like so:

builder.Register<Foo>()
    .WithParameter("url", resolver =>
    {
        var service = resolver.Resolve<ServiceA>();
        return service.GetUrl();
    });

@hadashiA
Copy link
Owner

Interesting.

However, since the lambda expression has the maximum degree of freedom, perhaps it can be replaced by.

builder.Register<Foo>(resolver =>
{
    var url = resolver.Resolve<ServiceA>().GetUrl();
    return new Foo(url, ..., ...);
});

I currently prefer to be able to do the same thing with a small number of flexible features rather than adding more features.

@hadashiA hadashiA closed this as completed Jul 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants