ssannandeji / Zenject-2019

Dependency Injection Framework for Unity3D
MIT License
2.53k stars 363 forks source link

WhenInjectedInto not working with generics #618

Open Xonoroff opened 5 years ago

Xonoroff commented 5 years ago

Hi! I ran into problem when I'm trying to use WhenInjectedInto method with generics. This method don't inject values into generics that should be resolved in future.

Code to reproduce listed below.


public class MainInstaller : MonoInstaller
{
    public override void InstallBindings()
    {
        Container.Bind<string>().FromInstance("Hello word").AsTransient().WhenInjectedInto(typeof(BaseAFactory<>));

        Container.Rebind<A>().FromIFactory(x=>x.To<BaseAFactory<A>>().AsTransient()).CopyIntoAllSubContainers();
        Container.Resolve<A>();
    }

}

public class A
{

}

public class BaseAFactory<T> : IFactory<T> where T : class, new()
{
    [Inject] protected string someStringValue;

    public virtual T Create()
    {
        Debug.LogWarning(someStringValue);
        return new T();
    }
}

P.S. I can use method When instead of WhenInjectedInto and use custom logic to check if class is generic, but in would be grate to have this opportunity in WhenInjectedInto method.

Xonoroff commented 5 years ago

P.S.S This behaviour is caused because under the hood you're using IsAssignableFrom. It's not working for generics correctly. The best way as for me to check if type is generic and compare generic type definitions.

        var factoryType = typeof(BaseAFactory<>); //here is BaseAFactory<T>
        var genericFactoryType = typeof(BaseAFactory<A>); //here is BaseAFactory<A>
        var isEqual = factoryType == genericFactoryType; //false because BaseAFactory<T> != BaseAFactory<A>
        var isAssignable = genericFactoryType.IsAssignableFrom(factoryType); // false
        var isImplements = genericFactoryType.IsGenericType && genericFactoryType.GetGenericTypeDefinition() == factoryType; //true because generic type for BaseAFactory<A> is BaseAFactory<T> and BaseAFactory<T> == BaseAFactory<T>