Usage
Sample interfaces/classes used can be found at the bottom of this page.
The Crosser Resolver contains 3 different ways to map interfaces to conrecte classes.
- Singleton<T>
- One<T>
- Many<T>
The resolver is static so you do not need to create any instance of the container.
All samples assumes that you have included the namespace for the static Crosser.Resolver
container.
// include the namespace
using Crosser.Resolve;
Singleton<T>
Use the Singleton<T>
to map and get singleton
objects.
Register
// set `IChuckNorris` to be a singleton that always returns the same instance of the implementation `TheOnlyChuck`
Singleton<IChuckNorris>.As(()=> new TheOnlyChuck());
Note that the As
method returns a boolean
telling if the registration was a success or not.
If you configure the ThrowErrorOnDeniedMapping
to true
the As
method will throw an exception if registration fails.
Resolve
// get the mapping for `IChuckNorris`
var theRealChuck = Singleton<IChuckNorris>.Get();
One<T>
Use One<T>
to map and get transient
objects
Register
// set IChuckNorris to map as transient (always return a new instance).
One<IChuckNorris>.As(()=> new TheOnlyChuck());
Note that the As
method returns a boolean
telling if the registration was a success or not.
If you configure the ThrowErrorOnDeniedMapping
to true
the As
method will throw an exception if registration fails.
Resolve
// get a new IChuckNorris
var chuck1 = One<IChuckNorris>.Get();
// get another chuck.
var chuck2 = One<IChuckNorris>.Get();
Many<T>
Many<T>
is grouped/enumerable transient
mapping where you can map several instances to one interface
.
Register
// map TheOnlyChuck and the FakeChuck to the IChuckNorris interface
Many<IChuckNorris>.Add(()=>new TheOnlyChuck());
Many<IChuckNorris>.Add(()=>new FakeChuck());
Note that the Add
method returns a boolean
telling if the registration was a success or not.
If you configure the ThrowErrorOnDeniedMapping
to true
the Add
method will throw an exception if registration fails.
Resolve
//Iterate over the IChuckNorris collection
foreach(var chuck in Many<IChuckNorris>.GetAll())
{
Console.WriteLine(chuck.GetFact());
}
Named instance
When working with collections of Many<T>
you migth wanna get a specific instance from the collection
Register
// map TheOnlyChuck to a named instance 'realchuck'
Many<IChuckNorris>.Add(() => new TheOnlyChuck(), namedInstance: "realchuck");
// add another instance, this time fake chuck without being named
Many<IChuckNorris>.Add(() => new FakeChuck());
Resolve
// get the named instance
var chuck = Many<IChuckNorris>.GetNamedInstance("realchuck");
Console.WriteLine(chuck.GetFact());
SingletonCollection<T>
SingletonCollection<T>
is grouped/enumerable singleton
mapping where you can map several singletons to one interface
.
Register
// map TheOnlyChuck and the FakeChuck to the IChuckNorris interface
SingletonCollection<IChuckNorris>.Add(()=>new TheOnlyChuck());
SingletonCollection<IChuckNorris>.Add(()=>new FakeChuck());
Note that the Add
method returns a boolean
telling if the registration was a success or not.
If you configure the ThrowErrorOnDeniedMapping
to true
the Add
method will throw an exception if registration fails.
Resolve
//Iterate over the IChuckNorris collection
foreach(var chuck in SingletonCollection<IChuckNorris>.GetAll())
{
Console.WriteLine(chuck.GetFact());
}
Named instance
When working with collections of SingletonCollection<T>
you migth wanna get a specific instance from the collection
Register
// map TheOnlyChuck to a named instance 'realchuck'
SingletonCollection<IChuckNorris>.Add(() => new TheOnlyChuck(), namedInstance: "realchuck");
// add another instance, this time fake chuck without being named
SingletonCollection<IChuckNorris>.Add(() => new FakeChuck());
Resolve
// get the named instance
var chuck = SingletonCollection<IChuckNorris>.GetNamedInstance("realchuck");
Console.WriteLine(chuck.GetFact());
Properties
The Crosser Resolver
let you add properties
to your mappings by passing in a IDictionary<string,object>
.
You may look at this as setting metadata to a mapping type.
One<T> & Singleton<T>
When mapping properties to One<T>
, Singleton<T>
the properties is mapped directly on the interface
of T
.
Register
/// Some properties to attach to a mapping
var props = new Dictionary<string, object>() { { "num", 123 }, { "str", "hello world" } };
// map TheOnlyChuck to IChuckNorris and pass in the properties
One<IChuckNorris>.As(() => new TheOnlyChuck(), properties: props);
Resolve
// get properties for IChuckNorris
var chuckProperties = One<IChuckNorris>.Properties;
Console.WriteLine("IChuckNorris has properties num:{0}, str:{1}", chuckProperties["num"], chuckProperties["str"]);
Many<T> & SingletonCollection<T>
When mapping properties
to Many<T>
& SingletonCollection<T>
the properties
is mapped to each mapping by type or named instance.
Creating some properties
for TheOnlyChuck
and FakeChuck
Register
// some properties for real chuck
var realChuckProps = new Dictionary<string, object>() { { "TheRealDeal", true } };
// some properties for fake chuck
var fakeChuckProps = new Dictionary<string, object>() { { "IAmFake", true } };
Map TheOnlyChuck
and FakeChuck
with properties
// map TheOnlyChuck to a named instance 'realchuck' with properties
Many<IChuckNorris>.Add(() => new TheOnlyChuck(), namedInstance: "realchuck", properties : realChuckProps);
// add another instance, this time fake chuck without being named but with properties
Many<IChuckNorris>.Add(() => new FakeChuck(), properties : fakeChuckProps);
Resolve
Get properties
by type of mapping.
var realChuckProperties = Many<IChuckNorris>.Properties<TheOnlyChuck>();
Console.WriteLine("TheOnlyChuck has property TheRealDeal:{0}", realChuckProperties["TheRealDeal"]);
var fakeChuckProperties = Many<IChuckNorris>.Properties<FakeChuck>();
Console.WriteLine("FakeChuck has property IAmFake:{0}", chuckProperties["IAmFake"]);
Since TheOnlyChuck
was mapped as a named instance realchuck
we can get the properties
by name as well
var realChuckProperties = Many<IChuckNorris>.Properties("realchuck");
Console.WriteLine("TheOnlyChuck has property TheRealDeal:{0}, realChuckProperties["TheRealDeal"]);
Rewritable
Having this feature might feel odd since you normally just remap the interface to a new concrete type. In Crosser
the default is that mappings IS NOT rewritable
.
The reason for this is that not all of our modules is supposed to be rewritable
. Also if developers create new custom modules they might wanna mark the mapping as not being rewritable
.
You might look at this as using the sealed
keyword but on mappings between interfaces and concrete types instead of a class.
You can rewrite both Singleton<T>
and Transient
(One<T>
and Many<T>
) mappings.
Register
Register a rewritable instance of Singleton<IChuckNorris>
to FakeChuck
Singleton<IChuckNorris>.As(() => new FakeChuck(), rewritable : true);
Whenever we ask for IChuckNorris
we will get the FakeChuck
, but since it is rewritable
we can change this by just adding a new mapping for IChuckNorris
.
Singleton<IChuckNorris>.As(() => new TheOnlyChuck());
Resolve
Now we will get TheOnlyChuck
when asking for IChuckNorris
Since we did not mark the new mapping as rewritable
this mapping is now sealed
and cant be changed.
var theOnlyChuck = Singleton<IChuckNorris>.Get();
Enable/Disable
If you want to disable/enable
mappings you can do so for all type of mappings. Singleton<T>
and One<T>
works in the same way, but Many<T>
has a different approach.
If a mapping is disabled it will return null
.
Singleton<T> One<T>
Since both Singleton<T>
and One<T>
returns a single instance the enable/disable
is straight forward.
One<IChuckNorris>.Enable();
One<IChuckNorris>.Disable();
And Singleton<T>
look the same
Singleton<IChuckNorris>.Enable();
Singleton<IChuckNorris>.Disable();
Many<T>
Many<T>
looks a little bit different since you can get 0-n
instances back. You can choose to enable/disable
ALL at once or do it individually by using the type of the concrete implementation.
Disable/Enable All
Many<IChuckNorris>.EnableAll();
Many<IChuckNorris>.DisableAll();
Disable/Enable by Type
Many<IChuckNorris>EnableAllOf<TheOnlyChuck>();
Many<IChuckNorris>DisableAllOf<FakeChuck>();
Disable by NamedInstance
This is currently not supported, although easy to add we have not yet seen the need for it in Crosser Framework
Reset
If you for some reason need to reset the resolver on a specific type you do so by calling
Singleton<T>.Reset();
or
One<T>.Reset();
or
Many<T>.Reset();
where T is the interface to reset the mappings for.
Configuration
The Crosser Resolver
has a static class for managing settings.
ThrowErrorOnDeniedMapping
This setting enables/disables exceptions to be thrown when registering One<T>.As(Expression<Func<T>> f)
and Singleton<T>.As(Expression<Func<T>> f)
This property is default set to false
Resolve.ResolverConfig.ThrowErrorOnDeniedMapping = false;
Sample Code
interfaces
and classes
used in this page
interface IChuckNorris
{
string GetFact();
}
public class TheOnlyChuck : IChuckNorris
{
public string GetFact()
{
return "Chuck Norris doesn't call the wrong number. You answer the wrong phone.";
}
}
public class FakeChuck : IChuckNorris
{
public string GetFact()
{
return "When Chuck Norris looks in the mirror nothing appears. There can never be a second Chuck Norris.";
}
}