defval / di

🛠 A full-featured dependency injection container for go programming language.
MIT License
232 stars 13 forks source link

Using `di.WithName()` breaks when having one entry without a `di.Name()` #16

Closed fionera closed 4 years ago

fionera commented 4 years ago

When I provide the Container with multiple implementations of an Object and have one that doesnt have a Name the container doesnt know how to resolve it properly and returns an error when resolving a named entry

erickskrauch commented 4 years ago

WithName just applies an additional alias to the definition but keeps its original type. So there is no error.

fionera commented 4 years ago

Here is an example of what I mean. The error is not very clear too

package main

import (
    "fmt"

    "github.com/goava/di"
)

func main() {
    c, err := di.New(
        di.Provide(NewOne),
        di.Provide(NewTwo, di.WithName("two")),
        di.Provide(NewThree, di.WithName("three")),
    )
    if err != nil {
        panic(err)
    }

    var one Example
    err = c.Resolve(&one)
    if err != nil {
        panic(err)
    }
    fmt.Println(one)

    var two Example
    err = c.Resolve(&two, di.Name("two"))
    if err != nil {
        panic(err)
    }
    fmt.Println(two)

    var three Example
    err = c.Resolve(&three, di.Name("three"))
    if err != nil {
        panic(err)
    }
    fmt.Println(three)
}

type Example string

func NewOne() Example {
    return "one"
}

func NewTwo(one Example) Example {
    return "two" + one
}

type ThreeParameters struct {
    di.Inject

    Two Example `di:"two"`
}

func NewThree(parameters ThreeParameters) Example {
    return parameters.Two + "three"
}
fionera commented 4 years ago

The same also happens if you have one entry in the container with an di.As Option and one or more without it.

defval commented 4 years ago

@fionera Sorry for the delay. I think this is not a feature :) #19 will solve the problem.

fionera commented 4 years ago

No problem ^^ I actually like the idea of supporting having multiple named and unnamed ones. But of course it would have to resolve it properly :)

defval commented 4 years ago

@fionera You can experiment with this function to get the desired result:

func findNamedProvider(plist *providerList, param parameter) (result provider, _ error) {
    for _, p := range plist.All() {
        if p.Name() == param.name {
            if result != nil {
                return nil, errHaveSeveralInstances{typ: param.typ}
            }
            result = p
        }
    }
    if param.name == "" && result == nil {
        return nil, errHaveSeveralInstances{typ: param.typ}
    }
    if result != nil {
        return result, nil
    }
    return nil, errParameterProviderNotFound{param: param}
}
fionera commented 4 years ago

Ah yeah I missinterpreted the test you wrote :) Looks awesome thx