z4kn4fein / stashbox

A lightweight, fast, and portable dependency injection framework for .NET-based solutions.
https://z4kn4fein.github.io/stashbox
MIT License
141 stars 10 forks source link

Register classes with interfaces without to inherit from it #99

Closed malibay81 closed 3 years ago

malibay81 commented 3 years ago

Hello again,

with v2.8.9 we used to Register classes with interfaces without to inherit from it. I.g. :

        interface ITest { }

        class Test1 { }
        class Test2 { }

        container.Register(typeof(ITest), typeof(Test1));
        container.Register(typeof(ITest), typeof(Test2));

        var tests = container.ResolveAll<ITest>();

Due to some breaking changes in v3.1.0 it's not possible anymore in this way.

Do you have any suggestion, to make these possible again?

z4kn4fein commented 3 years ago

Hey,

I'm pretty sure that didn't work with v2.8.9 either. ResolveAll() will return IEnumerable<ITest> in that case, but Test1 and Test2 won't fit into that type.

May I ask that what is the use case behind this usage? We might figure out something to solve the root issue. :)

malibay81 commented 3 years ago

Oops, sorry, that was my mistake.

You are right, ResolveAll does not work. Generic overloads of Resolve don't work either. But that's not our usage either, I'm sorry.

This is our usage with non generic functions:

   interface ITest { }

    class Test1 { }
    class Test2 { }

    container.Register(typeof(ITest), typeof(Test1));
    var instanceTest1 = container.Resolve(typeof(ITest));

    container.Register(typeof(ITest), typeof(Test2), config => { config.ReplaceExisting(); });
    var instanceTest2 = container.Resolve(typeof(ITest));

This time I tested it twice :-)

With v2.8.9 the test passes without errors.

With v3.5.1-preview-617 the test failed with the following exception:

    Exception has occurred: CLR/Stashbox.Exceptions.InvalidRegistrationException ...
    'Invalid registration with type STASHBOXTEST.UnitTest_StashboxContainer+Test1.
    Details: The type Test1 does not implement the service type ITest.'
z4kn4fein commented 3 years ago

Okay, that makes more sense, in that case just an object is returned. So just to make sure I understand your case correctly: are you using that interface only for service organization purposes? Is there a specific reason you don't want to make your services implement it?

Using the service type in this way feels a bit unnatural to me, this was one of the reasons why I introduced this check in the first place, to prevent accidental misconfigurations. Suppose someone tries to resolve this service with the generic API, it'll throw an invalid cast exception.

I know it's not a misconfiguration in your case, but still, it feels unnatural. As a quick solution, I could make the runtime type checks configurable, but I'd strongly recommend considering your services' organization around interfaces they actually implement.

malibay81 commented 3 years ago

Hi, I'm right there with you. For me it is also unnatural.

You don't need to change anything for that. I will adjust my code. I thought maybe there is a solution, which I don't see.

Thank you very much.