Is it possible to replace a registered type at runtime?

Apr 23, 2010 at 9:40 AM

Hi,

we have a scenario where the user can choose between different hardware at runtime. In the background we have several different hardware classes which all implement interfaces. We would like to use Unity to register the currently selected hardware instance with the interface. However, this would require to replace this registration at runtime when the user selects another hardware instance.

The following example might make this clearer:

public interface IHardware
{
    // some methods...
}

public class HardwareA : IHardware
{
    // ...
}

public class HardwareB : IHardware
{
    // ...
}


container.RegisterInstance<IHardware>(new HardwareA());

// user selects new hardware somewhere in the configuration...

// the following is invalid code, but can it be achieved another way?
container.ReplaceInstance<IHardware>(new HardwareB());

Can this behavior be achieved somehow?

BTW:  I am completely aware that instances which have already been resolved from the container will not be replaced with the new instances, of course. We would take care of that ourselves by forcing them to resolve the instance once again.

Apr 23, 2010 at 7:14 PM

Unity uses a "last in wins" policy for registrations. You can just call RegisterType or RegisterInstance again and it'll just work, and future requests will use the new registration.

Things to consider: 

Resolve is thread safe, registration is not. If you've got a multithreaded app and you may be resolving and registering at the same time, you need add appropriate locking so that only one thread is registering at a time, and no threads are resolving at the same time as one is registering.

Lifetime on reregistration can get "interesting". If the instance you're replacing was registered with the container controlled lifetime manager, be aware that the container is still holding on to that lifetime manager even after the registration is replaced. The instance in question will not be disposed until the container itself is disposed. If you plan on doing this on a regular basis, I recommend registering with the ExternallyControlledLifetimeManager and managing the lifetimes of those instances yourself.

Another option would be to use a child container, then at "reregister time" dispose the child container, create a new one, and register your new instance in the new child. But then you need to come up with a way to update references to the new child container, so that could be just as complicated.

 

 

Apr 26, 2010 at 9:22 AM

Thanks a lot for this pretty detailed answer! I did not know about that behavior. Thanks!

Apr 29, 2010 at 1:57 PM

What about registering both types when your app initializes, using an additional key?

 

public enum HardwareTypes {
	Hardware A,
        HardwareB
}

container.RegisterInstance<IHardware>(HardwareTypes.HardwareA.ToString(), new HardwareA());

container.RegisterInstance<IHardware>(HardwareTypes.HardwareB.ToString(), new HardwareB());

 

When resolving IHardware, pass in some variable (of type HardwareTypes) holding the desired hardware type.

container.Resolve<IHardware>(selectedHardwareType.ToString());

It's possible (maybe even probable) that the selectedHardwareType variable would be a static variable. You'll still need to deal with locking issues when changing the selectedHardwareType variable.

However, maybe this is less complicated than reconfiguring the container at runtime???

Apr 29, 2010 at 2:37 PM

@robertromito: Many thanks for your input! Actually, I have also thought about a similar approach lately. I will see which way to go in a few weeks. For now, I just wanted to ensure that it is possible to change the registration at runtime. But using your approach, this would not even be necessary.