Below are a bunch of randomly assorted examples of bindings that you might include in one of your installers.
For more examples, you may also be interested in reading some of the Unit tests (see Zenject/OptionalExtras/UnitTests
and Zenject/OptionalExtras/IntegrationTests
directories)
public override void InstallBindings()
{
// Create a new instance of Foo for every class that asks for it
Container.Bind<Foo>().AsTransient();
// Create a new instance of Foo for every class that asks for an IFoo
Container.Bind<IFoo>().To<Foo>().AsTransient();
// Non generic version of the above
Container.Bind(typeof(IFoo)).To(typeof(Foo)).AsTransient();
///////////// AsSingle
// Create one definitive instance of Foo and re-use that for every class that asks for it
Container.Bind<Foo>().AsSingle();
// Create one definitive instance of Foo and re-use that for every class that asks for IFoo
Container.Bind<IFoo>().To<Foo>().AsSingle();
// Bind the same instance to multiple types
// In this example, the same instance of Foo will be used for all three types
// (we have to use the non-generic version of Bind when mapping to multiple types)
Container.Bind(typeof(Foo), typeof(IFoo), typeof(IFoo2)).To<Foo>().AsSingle();
///////////// BindInterfaces
// This will have the exact same effect as the above line
// Bind all interfaces that Foo implements and Foo itself to a new singleton of type Foo
Container.BindInterfacesAndSelfTo<Foo>().AsSingle();
// Bind only the interfaces that Foo implements to an instance of Foo
// This can be useful if you don't want any classes to directly reference the concrete
// derived type
Container.BindInterfacesTo<Foo>().AsSingle();
///////////// FromInstance
// Use the given instance everywhere that Foo is used
// Note that in this case there's no good reason to use FromInstance
Container.Bind<Foo>().FromInstance(new Foo());
// This is simply a shortcut for the above binding
// This can be a bit nicer since the type argument can be deduced from the parameter
Container.BindInstance(new Foo());
// Bind multiple instances at once
Container.BindInstances(new Foo(), new Bar());
///////////// Binding primitive types
// BindInstance is more commonly used with primitive types
// Use the number 10 every time an int is requested
Container.Bind<int>().FromInstance(10);
Container.Bind<bool>().FromInstance(false);
// Or equivalently:
Container.BindInstance(10);
Container.BindInstance(false);
// You'd never really want to do the above though - you should almost always use a When condition for primitive values
Container.BindInstance(10).WhenInjectedInto<Foo>();
///////////// FromMethod
// Create instance of Foo when requested, using the given method
// Note that for more complex construction scenarios, you might consider using a factory
// instead with FromFactory
Container.Bind<Foo>().FromMethod(GetFoo);
// Randomly return one of several different implementations of IFoo
// We use Instantiate here instead of just new so that Foo1 gets its members injected
Container.Bind<IFoo>().FromMethod(GetRandomFoo);
// You an also use an anonymouse delegate directly
Container.Bind<Foo>().FromMethod(ctx => new Foo());
// This is equivalent to AsTransient
Container.Bind<Foo>().FromMethod(ctx => ctx.Container.Instantiate<Foo>());
InstallMore();
}
Foo GetFoo(InjectContext ctx)
{
return new Foo();
}
IFoo GetRandomFoo(InjectContext ctx)
{
switch (UnityEngine.Random.Range(0, 3))
{
case 0:
{
return ctx.Container.Instantiate<Foo1>();
}
case 1:
{
return ctx.Container.Instantiate<Foo2>();
}
}
return ctx.Container.Instantiate<Foo3>();
}
void InstallMore()
{
///////////// FromResolveGetter
// Bind to a property on another dependency
// This can be helpful to reduce coupling between classes
Container.Bind<Foo>().AsSingle();
Container.Bind<Bar>().FromResolveGetter<Foo>(foo => foo.GetBar());
// Another example using values
Container.Bind<string>().FromResolveGetter<Foo>(foo => foo.GetTitle());
///////////// FromNewComponentOnNewGameObject
// Create a new game object at the root of the scene and add the Foo MonoBehaviour to it
Container.Bind<Foo>().FromNewComponentOnNewGameObject().AsSingle();
// You can also specify the game object name to use using WithGameObjectName
Container.Bind<Foo>().FromNewComponentOnNewGameObject().WithGameObjectName("Foo1").AsSingle();
// Bind to an interface instead
Container.Bind<IFoo>().To<Foo>().FromNewComponentOnNewGameObject().AsSingle();
///////////// FromComponentInNewPrefab (singleton)
// Create a new game object at the root of the scene using the given prefab
// After zenject creates a new GameObject from the given prefab, it will
// search the prefab for a component of type 'Foo' and return that
GameObject prefab = null;
Container.Bind<Foo>().FromComponentInNewPrefab(prefab).AsSingle();
// Bind to interface instead
Container.Bind<IFoo>().To<Foo>().FromComponentInNewPrefab(prefab).AsSingle();
// You can also add multiple components
// Note here that only one instance of the given prefab will be
// created
// For this to work, there must be both a Foo MonoBehaviour and
// a Bar MonoBehaviour somewhere on the prefab
Container.Bind(typeof(Foo), typeof(Bar)).FromComponentInNewPrefab(prefab).AsSingle();
///////////// FromComponentInNewPrefab (Transient)
// Instantiate a new copy of 'prefab' every time an instance of Foo is
// requested by a constructor parameter, injected field, etc.
Container.Bind<Foo>().FromComponentInNewPrefab(prefab).AsTransient();
// Bind to interface instead
Container.Bind<IFoo>().To<Foo>().FromComponentInNewPrefab(prefab);
///////////// Identifiers
// Bind a globally accessible string with the name 'PlayerName'
// Note however that a better option might be to create a Settings object and bind
// that instead
Container.Bind<string>().WithId("PlayerName").FromInstance("name of the player");
// This is the equivalent of the line above, and is a bit more readable
Container.BindInstance("name of the player").WithId("PlayerName");
// We can also use IDs to bind multiple instances of the same type:
Container.BindInstance("foo").WithId("FooA");
Container.BindInstance("asdf").WithId("FooB");
InstallMore2();
}
// Then when we inject these dependencies we have to use the same ID:
public class Norf
{
[Inject(Id = "FooA")]
string _foo;
}
public class Qux
{
[Inject(Id = "FooB")]
string _foo;
}
public void InstallMore2()
{
///////////// AsCached
// In this example, we bind three instances of Foo, including one without an ID
// We have to use AsCached here because Foo is not a singleton, but we also
// do not want a new Foo created every time like AsTransient
// This will result in a maximum of 3 instances of Foo
Container.Bind<Foo>().AsCached();
Container.Bind<Foo>().WithId("FooA").AsCached();
Container.Bind<Foo>().WithId("FooA").AsCached();
InstallMore3();
}
// When an ID is unspecified in an [Inject] field, it will use the first
// instance
// Bindings without IDs can therefore be used as a default and we can
// specify IDs for specific versions of the same type
public class Norf2
{
[Inject]
Foo _foo;
}
// Qux2._foo will be the same instance as Norf2._foo
// This is because we are using AsCached rather than AsTransient
public class Qux2
{
[Inject]
Foo _foo;
[Inject(Id = "FooA")]
Foo _foo2;
}
public void InstallMore3()
{
///////////// Conditions
// This will make Foo only visible to Bar
// If we add Foo to the constructor of any other class it won't find it
Container.Bind<Foo>().AsSingle().WhenInjectedInto<Bar>();
// Use different implementations of IFoo dependending on which
// class is being injected
Container.Bind<IFoo>().To<Foo1>().AsSingle().WhenInjectedInto<Bar>();
Container.Bind<IFoo>().To<Foo2>().AsSingle().WhenInjectedInto<Qux>();
// Use "Foo1" as the default implementation except when injecting into
// class Qux, in which case use Foo2
// This works because if there is a condition match, that takes precedence
Container.Bind<IFoo>().To<Foo1>().AsSingle();
Container.Bind<IFoo>().To<Foo2>().AsSingle().WhenInjectedInto<Qux>();
// Allow depending on Foo in only a few select classes
Container.Bind<Foo>().AsSingle().WhenInjectedInto(typeof(Bar), typeof(Qux), typeof(Baz));
// Supply "my game" for any strings that are injected into the Gui class with the identifier "Title"
Container.BindInstance("my game").WithId("Title").WhenInjectedInto<Gui>();
// Supply 5 for all ints that are injected into the Gui class
Container.BindInstance(5).WhenInjectedInto<Gui>();
// Supply 5 for all ints that are injected into a parameter or field
// inside type Gui that is named 'width'
// Note that this is usually not a good idea since the name of a field can change
// easily and break the binding but shown here as an example of a more complex
// condition
Container.BindInstance(5.0f).When(ctx =>
ctx.ObjectType == typeof(Gui) && ctx.MemberName == "width");
// Create a new 'Foo' for every class that is created as part of the
// construction of the 'Bar' class
// So if Bar has a constructor parameter of type Qux, and Qux has
// a constructor parameter of type IFoo, a new Foo will be created
// for that case
Container.Bind<IFoo>().To<Foo>().AsTransient().When(
ctx => ctx.AllObjectTypes.Contains(typeof(Bar)));
///////////// Complex conditions example
var foo1 = new Foo();
var foo2 = new Foo();
Container.Bind<Bar>().WithId("Bar1").AsCached();
Container.Bind<Bar>().WithId("Bar2").AsCached();
// Here we use the 'ParentContexts' property of inject context to sync multiple corresponding identifiers
Container.BindInstance(foo1).When(c => c.ParentContexts.Where(x => x.MemberType == typeof(Bar) && x.Identifier == "Bar1").Any());
Container.BindInstance(foo2).When(c => c.ParentContexts.Where(x => x.MemberType == typeof(Bar) && x.Identifier == "Bar2").Any());
// This results in:
Assert.That(Container.ResolveId<Bar>("Bar1").Foo == foo1);
Assert.That(Container.ResolveId<Bar>("Bar2").Foo == foo2);
///////////// FromResolve
// FromResolve does another lookup on the container
// This will result in IBar, IFoo, and Foo, all being bound to the same instance of
// Foo which is assume to exist somewhere on the given prefab
GameObject fooPrefab = null;
Container.Bind<Foo>().FromComponentInNewPrefab(fooPrefab).AsSingle();
Container.Bind<IBar>().To<Foo>().FromResolve();
Container.Bind<IFoo>().To<IBar>().FromResolve();
// This will result in the same behaviour as the above
Container.Bind(typeof(Foo), typeof(IBar), typeof(IFoo)).To<Foo>().FromComponentInNewPrefab(fooPrefab).AsSingle();
InstallMore4();
}
public class FooInstaller : Installer<FooInstaller>
{
public FooInstaller(string foo)
{
}
public override void InstallBindings()
{
}
}
public class FooInstallerWithArgs : Installer<string, FooInstallerWithArgs>
{
public FooInstallerWithArgs(string foo)
{
}
public override void InstallBindings()
{
}
}
void InstallMore4()
{
///////////// Installing Other Installers
// Immediately call InstallBindings() on FooInstaller
FooInstaller.Install(Container);
// Before calling FooInstaller, configure a property of it
Container.BindInstance("foo").WhenInjectedInto<FooInstaller>();
FooInstaller.Install(Container);
// The arguments can also be added to the Installer<> generic arguments to make them
// strongly typed
FooInstallerWithArgs.Install(Container, "foo");
///////////// Manual Use of Container
// This will fill in any parameters marked as [Inject] and also call any [Inject] methods
var foo = new Foo();
Container.Inject(foo);
// Return an instance for IFoo, using the bindings that have been added previously
// Internally it is what is triggered when you fill in a constructor parameter of type IFoo
// Note: It will throw an exception if it cannot find a match
Container.Resolve<IFoo>();
// Same as the above except returns null when it can't find the given type
Container.TryResolve<IFoo>();
// Return a list of 2 instances of type Foo
// Note that in this case simply calling Resolve<IFoo> will trigger an exception
Container.BindInstance(new Foo());
Container.BindInstance(new Foo());
var foos = Container.ResolveAll<IFoo>();
// Create a new instance of Foo and inject on any of its members
// And fill in any constructor parameters Foo might have
Container.Instantiate<Foo>();
GameObject prefab1 = null;
GameObject prefab2 = null;
// Instantiate a new prefab and have any injectables filled in on the prefab
GameObject go = Container.InstantiatePrefab(prefab1);
// Instantiate a new prefab and return a specific monobehaviour
Foo foo2 = Container.InstantiatePrefabForComponent<Foo>(prefab2);
// Add a new component to an existing game object
Foo foo3 = Container.InstantiateComponent<Foo>(go);
}