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

Come up with an API that will allow injecting values in bindings based on lambda functions using local variables #61

Open
NikolayPianikov opened this issue May 27, 2024 · 4 comments
Labels
enhancement New feature or request

Comments

@NikolayPianikov
Copy link
Member

Idea suggested by @ekalchev here.

@NikolayPianikov
Copy link
Member Author

The API should be based on this interface, so that it would be possible to distinguish calls from custom lambda function logic belonging to the binding.

@NikolayPianikov NikolayPianikov added the enhancement New feature or request label May 27, 2024
@ekalchev
Copy link

ekalchev commented May 27, 2024

My idea comes from the usage of Unity DI. There is a concept of constructor override and dependency override.

https://www.tutorialsteacher.com/ioc/overrides-in-unity

The idea is to replace a specific constructor parameter for which you don’t have a registration, or you have a registration but in this particular resolve, you want to use a specific value for a type that is different from the registered one.

DependencyOverride works not only for the class you currently resolve but also for all dependencies down the dependency tree that have that dependency type in their constructors. As the name suggests, it overrides all dependencies down the dependency tree.

I can guess that the latter will be complex to implement.

ParameterOverride should be easy to implement—it overrides just a single parameter from the list of parameters of the constructor by matching the parameter name. With reflection-based DI, that approach was very fragile, and I was cautious to use it because if someone renames the parameter, you lose your override and you don’t get any errors indicating the problem. With a source generator, this can be made very durable and have a compile-time error if ParameterOverride doesn’t match a constructor parameter name or type.

Having this, you can pass a specific constructor parameter without the need to specify the others, as they can be picked up from known registrations. This is very convenient because when you add more parameters to the constructor, you won’t need to update the registration code if you already have this type registered.

@NikolayPianikov
Copy link
Member Author

NikolayPianikov commented Jun 10, 2024

@ekalchev could you please review the approach in the examples Tag on injection site and
Tag on injection site with wildcards. This approach works for all dependencies. At the moment it is difficult to do local overriding of bindings inside a factory - too many variants and complex graph.

@ekalchev
Copy link

ekalchev commented Jun 11, 2024

DI.Setup(nameof(Composition))
    .Bind(Tag.On("*Service:dependency1", "*Consumer:myDep"))
        .To<AbcDependency>()
    .Bind(Tag.On("*Service:dependency2", "*Service:Dependency3"))
        .To<XyzDependency>()
    .Bind().To<Consumer<TT>>()
    .Bind<IService>().To<Service>()

Isn't it better to annotate somehow those registration with dependency override syntax

.Bind().To<Consumer<TT>>()
.Bind<IService>().To<Service>()

instead of annotating the constructor argument types?

.Bind<IDependency>("mydep").To<XyzDependency>()
.Bind().To<Consumer<TT>>().DependencyOverride<IDependency>("mydep")

if you want to override constructor parameter by name

.Bind<IDependency>("mydep1").To<XyzDependency>()
.Bind<IDependency>("mydep2").To<AbcDependency>()
.Bind().To<Service>()
     .ConstructorParameterOverride("dependency1", "mydep1")
     .ConstructorParameterOverride("dependency2", "mydep2")

I believe this syntax is easy to understand and when you inspect an type registration you immediately can spot overrides to a specific type or constructor argument.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants