I know the purpose of SimpleInjector's LifestyleMismatch exception and why it throws it. But suppose to have:
Players.dll
public abstract class PlayerEqualizer { ... }
public abstract class Player : IPlayer, ISongAware
{
public Player(PlayerEqualizer eq)
{
Equalizer = eq;
}
public PlayerEqualizer Equalizer { get; }
public abstract void StartPlay();
}
Players.Rock.dll
public class RockPlayerEqualizer : PlayerEqualizer {}
public class RockPlayer : Player
{
public RockPlayer(RockPlayerEqualizer eq) : base(eq) {}
public override void StartPlay() { ... }
}
public class RnBPlayer : Player
{
public RnBPlayer(RockPlayerEqualizer eq) : base(eq) {}
public override void StartPlay() { ... }
}
Players.Pop.dll
public class PopPlayerEqualizer : PlayerEqualizer{}
public class PopPlayer : Player
{
public PopPlayer(PopPlayerEqualizer eq) : base(eq) {}
public override void StartPlay() { ... }
}
All the implementation of Player
are registered as a collection of IPlayer
and all the registrations are singleton:
var registrations = container
.GetTypesToRegister(typeof(IPlayer), assemblies)
.Select(t => Lifestyle.Singleton.CreateRegistration(t, container));
foreach (var registration in registrations)
{
container.AddRegistration(registration.ImplementationType, registration);
}
container.RegisterCollection<IPlayer>(registrations);
container.RegisterCollection<ISongAware>(container.GetCurrentRegistrations()
.Where(ip => typeof(ISongAware).IsAssignableFrom(ip.ServiceType))
.Select(ip => ip.Registration));
All
container.GetInstance<RockPlayer>
container.GetAllInstances<IPlayer>
container.GetAllInstances<ISongAware>
must return the same instance, so the IPlayer
registrations must be singleton. Doing so, all the PlayerEqualizer
must be singleton as well, since they are dependency of a singleton registration, but the PlayerEqualizer
implementation aren't singleton (RockPlayer
and RnBPlayer
both depend on RockPlayerEqualizer
but they need different instances).
The only solution I could find is to set the SimpleInjector container.Options.SuppressLifestyleMismatchVerification
flag to False
but I don't want to lose that feature... Another option could be call the SuppressDiagnosticWarning
method on the IPlayer
's registrations but despite I couldn't get it to work, my real concern is that these solutions are just workaround...
Am I missing something?
What you want is not to register PlayerEqualizer
instances as Transient but as Instance Per Dependency.
Technically, both lifestyles are the same, as they both return new instances on every request. The intend of Instance per Dependency is however, very different, because:
Each consumer will get a new instance of the given service type and that dependency is expected to get live as long as its consuming type.
While with Transient the intention is the dependency to be short-lived.
This lifestyle is deliberately left out of Simple Injector, because:
its usefulness is very limited compared to the Transient lifestyle. It ignores lifestyle mismatch checks and this can easily lead to errors, and it ignores the fact that application components should be immutable. In case a component is immutable, it’s very unlikely that each consumer requires its own instance of the injected dependency.
The project's Code Samples however contains the definition of a InstancePerDependencyLifestyle that does what you want it do do:
You can use this lifestyle as follows:
container.Register<RockPlayerEqualizer>(new InstancePerDependencyLifestyle());
UPDATE:
Do note that your configuration can be simplified to the following:
var playerTypes = var registrations = container
.GetTypesToRegister(typeof(IPlayer), assemblies);
foreach (Type playerType in playerTypes)
{
container.Register(playerType, Lifestyle.Singleton);
}
container.RegisterCollection<IPlayer>(assemblies);
container.RegisterCollection<ISongAware>(assemblies);