/// Instantiate an instance of a Factory return type from the current
/// context. If the Factory is a Command, attempts to invoke the command
/// using the supplied arguments, provided the arguments contain the
/// necessary parameter values the command needs. If not, we then look
/// to see if any alternate Factories have been registered, looking to
/// see which of these might succeed from the current context.
private object Instantiate(Factory step, Dictionary <string, object> args)
{
object ctxt = null;
_log.TraceFormat("Attempting to create an instance of {0} via {1}", step.ReturnType, step);
if (step.IsConstructor)
{
ctxt = InvokeConstructor(step.Constructor);
}
else if (step.IsProperty)
{
ctxt = step.Property.GetValue(this[step.DeclaringType], new object[] {});
}
else if (step.IsCommand)
{
if (args.ContainsRequiredValuesForCommand(step.Command))
{
ctxt = InvokeCommand(step.Command, args);
}
else
{
// Check for alternate factories
foreach (var factory in _registry.GetAlternates(step.ReturnType))
{
if (!factory.IsCommand || args.ContainsRequiredValuesForCommand(factory.Command))
{
step = factory;
ctxt = Instantiate(factory, args);
break;
}
}
}
if (ctxt == null && MissingArgHandler != null)
{
// Call missing arg handler for each missing arg
foreach (var param in step.Command.Parameters)
{
if (!args.ContainsValueForSetting(param))
{
args[param.Name] = MissingArgHandler(param);
}
}
}
if (ctxt == null && args.ContainsRequiredValuesForCommand(step.Command))
{
ctxt = InvokeCommand(step.Command, args);
}
}
else
{
throw new Exception(string.Format("Unrecognised factory type: {0}", step));
}
if (ctxt != null)
{
Set(ctxt);
if (step.IsSingleUse)
{
_purgeList.Add(ctxt);
}
}
else
{
throw new ContextException(string.Format("No object of type {0} can be constructed " +
"from the current context, using the supplied arguments", step.ReturnType));
}
return(ctxt);
}