I'm a rookie in Prism and in particular in .NET environment.
This is a brief description around the problem:
I have a hierarchy of several interfaces (IRobot
, IHuman
, IElf
, IVampire
, ISaiyan
) childs of the same parent interface (IPlayer
). Each leaf-interface has of course its implementation classes (Robot
, Human
, Elf
, Vampire
, Saiyan
). The IPlayer
has the method void Initialize()
.
In the GameModule
class (child of Prism.Modularity.IModule
) there is the registration of all the implementations, to the same parent interface, as singletons:
public class GameModule: IModule
{
private void RegisterPlayers(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IPlayer, Robot>();
containerRegistry.RegisterSingleton<IPlayer, Human>();
[...]
}
}
Later, in the BattleGrid
I need to resolve all these implementations to call the same method Initialize()
in this way:
public class BattleGrid
{
private readonly IEnumerable<IPlayer> _players;
public BattleGrid(IEnumerable<IPlayer> players){
_players = players;
}
public void InitializeAllPlayers() => _players .ForEachDo(player=>player.Initialize());
}
Unfortunately this is not working. How can I resolve it?
Right now I used this "double-registration trick" but I don't like it very much: in the GameModule
class I register first all the implementations with the related interface, then I register a list of IPlayer
by resolving each interface registred:
public class GameModule: IModule
{
private void RegisterPlayers(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterSingleton<IRobot, Robot>();
containerRegistry.RegisterSingleton<IHuman, Human>();
[...]
containerRegistry.RegisterSingleton<IEnumerable<IPlayer>>(
container => new List<IPlayer>
{
container.Resolve<IRobot>(),
container.Resolve<IHuman>(),
[...]
}
);
}
}
I don't like it because another developer will struggle for hours before he/she found this "double registration trick".
Sorry, I misunderstood your question. It seems like you need automatic discovery, for scanning and registering your implementations.
Scan all loaded assemblies for types that implement IPlayer
and register each as a singleton. No sweat.
public static class ContainerRegistryExtensions
{
public static void RegisterAllPlayers<T>(this IContainerRegistry containerRegistry)
{
var playerType = typeof(T);
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var playerImplementations = assemblies
.SelectMany(a => a.GetTypes())
.Where(t => playerType.IsAssignableFrom(t) && !t.IsAbstract && t.IsClass);
foreach (var implementation in playerImplementations)
{
containerRegistry.RegisterSingleton(playerType, implementation);
}
}
}
The extension method scans all loaded assemblies for types that implement IPlayer
.
public class GameModule : IModule
{
public void RegisterTypes(IContainerRegistry containerRegistry)
{
containerRegistry.RegisterAllPlayers<IPlayer>();
}
public void OnInitialized(IContainerProvider containerProvider)
{
// Initialization logic if needed
}
}
Now adding new implementations of IPlayer
only requires creating the class, no changes needed in the registration logic.