-
Notifications
You must be signed in to change notification settings - Fork 366
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
Add support for convention based binding #24
Comments
It is an very important feature to have in a DI-framework which was one of the reasons I immediately felt in love with Structuremap 10 years ago :) , Autofac and other major DI-frameworks has it as well now. The reason for scanning and/ or convention-based binding is that polymorphism is working flawlessly making it even more powerful to utilize a DI-framework. One more thing to mention regarding binding, is the fantastic feature called open generics, this is where the world of magic opens up and you wonder if you ever will wake up from the dream. |
Yep, this is supported in Zenject 4, along with lots of other improvements, which is just a few days away from being ready to use. As for open generics, I'm assuming you're talking about doing stuff like this?
This has been supported for a long time but I haven't personally used it much. Maybe there are some interesting design choices with it that I'm missing By the way, if you are already familiar with StructureMap, AutoFac, etc. I would love to hear more feedback :) Before working in Unity3D I only really used Ninject so I don't have much else to compare it to |
Sorry, for the delay. I somehow missed the reply. For readers: suppose we have different implementations of EnemyBrain: interface IEnemyBrain<T>
void Think(T go); and: class EnemyBrain: IEnemyBrain<Clever>
void Think(Clever clever)
{
clever.ExtendedPositionAwareness(....
}
class EnemyBrain: IEnemyBrain<Idiot>
void Think(Idiot idiot)
{
idiot.SimpleStupidPositionAwareness(....
} We could then do something like: class Enemy(IEnemyBrain<Clever> brain)
{
void Update()
brain.Think();
}
class Enemy(IEnemyBrain<Idiot> brain)
{
void Update()
brain.Think()
} Seems a bit tedious at first, but the smart thing is that all the wiring is done automatically and follow separation of concerns nicely. |
Hello svermeulen Just tested this with generics but couldn't get it to work. Validation failed. public interface IFoo<T>
{
string Bar(T t);
}
public class FooString:IFoo<string>
{
public string Bar(string s)
{
return s;
}
}
public class FooInt : IFoo<int>
{
public string Bar(int s)
{
return s.ToString();
}
} Install Bindings: Container.Bind(typeof(IFoo<>)).AsSingle();
var expectedInstanceOfFooString = Container.Resolve<FooString>();
var expectedInstanceOfFooString = Container.Resolve<IFoo<string>>();
var expectedInstanceOfFooInt = Container.Resolve<IFoo<int>>(); Cannot resolve any of them. Maybe the binding parameters are wrong? Not sure if this can help, but normally I do like this in StructureMap:http://structuremap.github.io/generics/ , pay attention to : x.ConnectImplementationsToTypesClosing(typeof(IVisualizer<>)); Of course I can do the mapping by hand, but it would be really nice to have support for open generics scanning. |
Ok I looked into this a bit. This binding:
Doesn't make any sense given the way the Zenject interprets it. That means that Zenject should instantiate an instance of the interface In Zenject you have to explicitly declare every mapping from the "contract type" to the "concrete instantiated type". So I think you're trying to do this:
This code almost works, except that the |
Excellent... |
Actually you could do it this way too:
When doing convention based binding, Zenject will throw away any bindings that do not derive from the contract type, so you can just bind to But again, there's an issue with open types not being handled correctly when used with interfaces somewhere that needs to be fixed first |
Hi, Not sure if this is something that could be used inside the Zenject code, but it works for my purpose:
I use it as follow:
|
I committed a fix just now that allows things like this to work:
|
Hi! public class MainInstaller : MonoInstaller<MainInstaller>
{
public override void InstallBindings()
{
Container.Bind<IA>().To<A>().AsTransient();
Container.Bind<IB>().To<B>().AsTransient();
Container.Bind(typeof(IFoo<>)).To(typeof(Foo<>)).AsSingle();
Container.Bind<Tester>().ToSelf().AsSingle().NonLazy();
}
public class Tester
{
public Tester(IFoo<IA> a, IFoo<IB> b){}
}
public class A : IA {}
public class B : IB {}
public interface IB {}
public interface IA{}
public class Foo<T> : IFoo<T>
{
public Foo()
{
Debug.LogWarning(typeof(T));
}
}
public interface IFoo<T>{}
} and it throws this exception on resolving
So I guess it still doesn't work. |
@Vorlex Your example runs now on develop branch, thanks for the report As far as I know the issues with open generics are fixed now so closing this |
In some cases it can be tedious to, for example, add every binding to ITickable or IInitializable explicitly in the installer. What would be useful is if you could define generic conventions to always handle cases like this. We could use another fluent interface, something like the following (which is largely taken from what other DI frameworks look like)
The text was updated successfully, but these errors were encountered: