-
Notifications
You must be signed in to change notification settings - Fork 2
Collection injection
Spring.NET allows to configure object dependencies with a collection, where collection items are plain values, internal objects or object references. Spring.FluentContext offers API to express that kind of configuration in code, which is available for dependency injection via constructor arguments or property setters.
If BindProperty() or BindConstructorArg() refers to array, collection or dictionary type, it is possible to configure it with generic To() binding method and one of following definition types: Def.Array(), Def.List(), Def.Dictionary().
All of above collections are accepting definitions of collection items instead of real collection items. This feature allows to insert plain values (by using Def.Value()), existing object references (by using Def.Reference()) or object definitions (by using Def.Object()).
The following example presents configuration of array:
class Cat { /* ... */}
class CatKeeper
{
public Cat[] Cats { get; set; }
}
// ...
var kitty = ctx.RegisterUniquelyNamed<Cat>()
.BindProperty(c => c.Name).ToValue("Kitty")
.GetReference();
ctx.RegisterDefault<Cat>()
.BindProperty(c => c.Name).ToValue("Street Cat");
ctx.RegisterDefault<CatKeeper>()
.BindProperty(k => k.Cats).To(Def.Array(
Def.Reference<Cat>(), //with registered default
kitty, //with IObjectRef
Def.Object<Cat>(cat => cat.BindProperty(c => c.Name).ToValue("Domestic Cat")), //with inline
Def.Value(new Cat { Name = "Misty" }))); //with value - object not configured by context
The example above presents configuration of Cats
property with Def.Array(), where each element of array is configured differently.
Please note that the configuration of lists is done in the same way but with Def.List() definition.
The configuration of dictionaries with Def.Dictionary() definition looks a little bit differently, because dictionary is filled with key-value pairs.
There two methods of populating dictionary - one with fluent syntax, and one with standard dictionary syntax. The following example shows the same configuration done in both ways:
class Car { /* ... */ }
class Motorcycle { /* ... */ }
class Computer { /* ... */ }
class Shop { /* ... */ }
class Distributor
{
public IDictionary<Type, Shop> ProductMap { get; set; }
}
// ...
ctx.RegisterNamed<Shop>("electronic")
.BindProperty(s => s.Name).ToValue("Electronic Store");
var motoStore = ctx.RegisterUniquelyNamed<Shop>()
.BindProperty(s => s.Name).ToValue("Moto Store")
.GetReference();
ctx.RegisterNamed<Distributor>("fluent").BindProperty(d => d.ProductMap).To(
Def.Dictionary<Type, Shop>(dict => dict
.Set(Def.Value(typeof(Car)), motoStore)
.Set(Def.Value(typeof(Motorcycle)), motoStore)
.Set(Def.Value(typeof(Computer)), Def.Reference<Shop>("electronic"))));
ctx.RegisterNamed<Distributor>("dictionaryLike").BindProperty(d => d.ProductMap).To(
Def.Dictionary<Type, Shop>(dict =>
{
dict[Def.Value(typeof(Car))] = motoStore;
dict[Def.Value(typeof(Motorcycle))] = motoStore;
dict[Def.Value(typeof(Computer))] = Def.Reference<Shop>("electronic");
}));
Spring.FluentContext offers also extension methods that simplifies creation of collections. Depending on bound property/constructor argument type, a following methods may become available for use: ToArray(), ToList(), ToDictionary().
The following code block presents this feature. With usage of those extension methods, configuration code is shorter:
class Cat { /* ... */}
class CatKeeper
{
public Cat[] Cats { get; set; }
}
// ...
var kitty = ctx.RegisterUniquelyNamed<Cat>()
.BindProperty(c => c.Name).ToValue("Kitty")
.GetReference();
ctx.RegisterDefault<Cat>()
.BindProperty(c => c.Name).ToValue("Street Cat");
ctx.RegisterDefault<CatKeeper>()
.BindProperty(k => k.Cats).ToArray(
Def.Reference<Cat>(), //with registered default
kitty, //with IObjectRef
Def.Object<Cat>(cat => cat.BindProperty(c => c.Name).ToValue("Domestic Cat")), //with inline
Def.Value(new Cat { Name = "Misty" })); //with value - object not configured by context
class Car { /* ... */ }
class Motorcycle { /* ... */ }
class Computer { /* ... */ }
class Shop { /* ... */ }
class Distributor
{
public IDictionary<Type, Shop> ProductMap { get; set; }
}
// ...
ctx.RegisterNamed<Shop>("electronic")
.BindProperty(s => s.Name).ToValue("Electronic Store");
var motoStore = ctx.RegisterUniquelyNamed<Shop>()
.BindProperty(s => s.Name).ToValue("Moto Store")
.GetReference();
ctx.RegisterNamed<Distributor>("fluent")
.BindProperty(d => d.ProductMap).ToDictionary(dict => dict
.Set(Def.Value(typeof(Car)), motoStore)
.Set(Def.Value(typeof(Motorcycle)), motoStore)
.Set(Def.Value(typeof(Computer)), Def.Reference<Shop>("electronic")));
ctx.RegisterNamed<Distributor>("dictionaryLike")
.BindProperty(d => d.ProductMap).ToDictionary(dict =>
{
dict[Def.Value(typeof(Car))] = motoStore;
dict[Def.Value(typeof(Motorcycle))] = motoStore;
dict[Def.Value(typeof(Computer))] = Def.Reference<Shop>("electronic");
});
Please note that if collection item is implementing IDisposable interface, then context dispose it properly on its destruction, even if collection item was defined inline as unnamed object (see Constructor class registration in CollectionInjectionExample.cs)
Go back to: Table of Contents