Resolving injected instances when using Activator.CreateInstance

3k views Asked by At

I'm trying to figure out how to have Castle Windsor resolve dependancies for objects created using Activator.CreateInstance.

Currently when I create objects this way, the dependancies inside the created object do not get resolved. I've had a search around to see if there's a Windsor method that does the same thing whilst also resolving the dependancies but I haven't found anything thus far.

As for why I'm creating instances this way, I'm playing about with a basic text game for a bit of fun and the instances are being created based on user input commands and so I need to create the instance based on a string (currently the command is mapped in a Dictionary to a type which is then created using the above method).

Thanks for any and all help.

3

There are 3 answers

1
Felice Pollano On BEST ANSWER

AFAIK you can register in castle windsor you can register the so called "named instances" so you can create the object you need by resolving them througth the container without dealing with Activator.CreateInstance that for sure can't perform IoC. Basically you have to register your component with a key:

AddComponent(String key, Type classType) 

and then call

Resolve(string Key)

to have back your component properly created with all dependencies resoved.

1
mookid8000 On

A better implementation, Windsor-wise, would be to utilize a typed factory. With a typed factory, your code would not have to reference the container, because a factory implementation would be automatically created for you.

With a typed factory, your factory could look like this:

public interface IUserInputCommandFactory
{
    IUserInputCommand GetMove();
    IUserInputCommand GetLocate();
    IUserInputCommand GetLookAround();
    IUserInputCommand GetBag();
}

and Windsor would forward each factory method to a corresponding resolve - e.g. GetMove would become container.Resolve<IUserInputCommand>("Move").

See typed factory docs ("'get' methods lookup by name) for more information.

I think this is one of the places where Windsor really shines :)

0
Jamie Dixon On

To expand on the answer given by Felice I thought it'd be useful to post the solution I came to based on the accepted answer.

Currently my commands are mapped via an IDictionary<TKey,TValue> but will be moved to another medium soon (XML, JSON, etc).

Here's how I'm registering the compnents for user input commands:

public void InstallUserCommands(IWindsorContainer container)
{

  var commandToClassMappings = new Dictionary<string, string>
                            {
                              {"move", "MoveCommand"},
                              {"locate","LocateSelfCommand"},
                              {"lookaround","LookAroundCommand"},
                              {"bag","LookInBagCommand"}
                            };

  foreach (var command in commandToClassMappings)
  {
     var commandType = Type.GetType("TheGrid.Commands.UserInputCommands." + command.Value);
     container.Register(Component.For(commandType).Named(command.Key));

  }
}

and to resolve the instance:

public UserCommandInputMapperResponse Invoke(UserCommandInputMapperRequest request)
{
  var container = new WindsorContainer();
  container.Install(FromAssembly.This());

  IUserInputCommand instance;

  try
  {
    instance = container.Resolve<IUserInputCommand>(request.CommandName.ToLower().Trim());
  }
  catch (Exception)
  {
     instance = null;
   }

   return new UserCommandInputMapperResponse
                {
                   CommandInstance = instance
                };
}