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());
Info

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());
Info

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());
Info

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());
Info

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.";
    }
}