Register Type with name

Topics: Feature requests
Aug 21, 2012 at 6:44 AM
Edited Aug 21, 2012 at 6:45 AM

In the unitycontainer its possible to register a Object with a name.

So i can resolve multiple objects of the same type, with different names.

For Example 

IoCHelper.UnityContainer.RegisterType<ViewModelContainer>("FirstContainer"new ContainerControlledLifetimeManager());
IoCHelper.UnityContainer.RegisterType<ViewModelContainer>("SecondContainer"new ContainerControlledLifetimeManager());

How to solve something like that in the ServiceLocator of Catel?

Coordinator
Aug 21, 2012 at 8:36 AM

This is not supported in the ServiceLocator. Can you give a real-life scenario why this feature should be implemented?

Aug 21, 2012 at 9:35 AM

You have different PleaseWaitService for Example. Both have the Interface IPleaseWaitService.

The first dimm the background, the second don't dimm the background but have an cancel button and so on.

I think there are a lots of examples. The reason why the unity container have implemented this.

I need this in relation with the viemodelmanager.

Coordinator
Aug 21, 2012 at 9:53 AM

Hmmm, we cannot write this for 3.3, but maybe we can add it in 3.4. You can create a workitem for it, or even better, create a fork with pull request ;)

Aug 21, 2012 at 11:03 AM

I think a work item is ok ;-).

Until that I use the unitycontainer.

Developer
Aug 21, 2012 at 12:59 PM

Keep in mind during the execution of synchronization with external containers, if the external container is Unity then we have to register the named instances.

Developer
Aug 21, 2012 at 1:00 PM

Keep in mind during the execution of synchronization with external containers, if the external container is Unity then we have to register the named instances.

Aug 22, 2012 at 2:33 AM

It will be very useful. I have 120 technical indicators implementing IIndicator interface. The user selects indicator from a TreeView by name. So I have to instantinate the proper indicator by calling something like: 

var indicator = ServiceLocator.Instance.ResolveType<IIndicator>("Moving Average");

Aug 22, 2012 at 5:09 AM

issue created: http://catel.codeplex.com/workitem/7185

Aug 22, 2012 at 5:33 AM
alexfdezsauco wrote:

... then we have to register the named instances.

Yes, like in my example:

IoCHelper.UnityContainer.RegisterType<ViewModelContainer>("SecondContainer"new ContainerControlledLifetimeManager());

or what do you mean?

Coordinator
Aug 22, 2012 at 7:19 PM

We have to think carefully about this because we support lots of external containers. For example, if Unity is the only external container supporting this, what about the others? Should we throw exceptions, swallow them, etc.

What I would do in such a case is create a Manager. Maybe we will provide a base implementation like this:

public class IndicatorManager : Manager<IIndicator>
{
    
}

then you can register the Manager<IIndicator> in the service locator, and use that to retrieve the named instance. Makes it compatible with all other containers as well.

The manager base class will just be a dictionary by name (or maybe you can even specify it by using Manager<string, IIndicator>.

What do you think?

Aug 23, 2012 at 3:42 AM

You are absolutely right. I'm using now a factory class that stores indicators in a Dictionary<string, Indicator>

So the only thing I have to do is to register the IndicatorFactory in the ServiceLocator as a Singleton.

var indFactory= ServiceLocator.Instance.ResolveType<IIndicatorFactory>();
var indicator = indFactory.GetIndicator("Moving Average");

Coordinator
Aug 23, 2012 at 10:09 AM

Can you share your implementation of the Factory base? Then we can add it to Catel for cases like this.

Aug 23, 2012 at 1:16 PM

My current implementation is too specific. That's why I'm trying to decouple it.

Code is here IndicatorStore 

Here is an adopted summery:

public static class IndicatorStore
{
	private static readonly Dictionary<string, Indicator> OriginalIndicators = new Dictionary<string, Indicator>();

	public static void AddOriginalIndicators()
	{
		OriginalIndicators.Add("Accelerator Oscillator", new Accelerator_Oscillator(SlotTypes.NotDefined));
		OriginalIndicators.Add("Account Percent Stop", new Account_Percent_Stop(SlotTypes.NotDefined));
		OriginalIndicators.Add("Accumulation Distribution", new Accumulation_Distribution(SlotTypes.NotDefined));
		// ...
	}
	
	// Gets new instance
	public static Indicator ConstructIndicator(string indicatorName, SlotTypes slotType)
	{
		Type indicatorType = OriginalIndicators[indicatorName].GetType();
		var parameterType = new[] {slotType.GetType()};
		ConstructorInfo constructorInfo = indicatorType.GetConstructor(parameterType);
		if (constructorInfo != null)
			return (Indicator) constructorInfo.Invoke(new object[] {slotType});

		return null;
	}
	
	// Gets singleton (Not Implemented)
	public static Indicator GetIndicator(string indicatorName)
	{
		return OriginalIndicators[indicatorName];
	}
}

 I actually construct a new instance with sending a constructor parameter. If we want to include such functionality in ServiceLocator it should be:

bool IsNewInstance = true; // Singleton or new instance;
object[] ctrParams = new object[] {param1, param2, ...};
var indicator = ServiceLocator.Instance.ResolveType<IIndicator>("Moving Average", IsNewInstance, ctrParams);

But as I said, it's too specific and probably it's not necessary to include in Core.

Here is interesting the way how I construct a new instance from an object. We can use this in Catel. Register singleton and resolve singleton as usual. If we need a new instance, we can call something as: 

var indicator = ServiceLocator.Instance.ResolveNewInstanceFromType<IIndicator>();
to call (Indicator) constructorInfo.Invoke();
Coordinator
Aug 23, 2012 at 1:20 PM

Great, thanks for sharing!