简体   繁体   中英

C# IoC: Implementing conditional injection

I want to create a simple game and use one of IoC containers. Every game has players, so I want to inject them into Game class. The thing is, there could be different types of players. First player will be always Human (device owner;)), but his opponent: Human (play and pass), Bot or Online (human, but playing through internet).

Here is the code. There different players:

public class Human : IPlayer
{
    public int Id { get; set; }
    public string Name { get; set; }
    public PlayerType Type { get; set; }
}

public class Bot : Human
{
}

public class OnlinePlayer : Human
{
}

public interface IPlayer
{
    int Id { get; set; }
    string Name { get; set; }
    PlayerType Type { get; set; }
}

and Game class:

public class Game : IGame
{
    public GameType Type { get; private set; }
    public List<IPlayer> Players { get; private set; }

    public Game(GameType type, List<IPlayer> players)
    {
        Type = type;
        Players = players;
    }
}

public interface IGame
{
    GameType Type { get; }
    List<IPlayer> Players { get; }
}

As you can see, I inject List of players in Game's container. Here is my question:

How can I resolve List<IPlayer> in case of differen type GameType ?

if GameType = Single player -> Inject Human and Bot

if GameType = Pass and play -> Inject Human and Human

if GameType = Online game -> Inject Human and OnlinePlayer

There's no reason to make it more complicated than it has to be. You can put something like this in an Abstract Factory :

if (gameType == GameType.Single)
    return new Game(
        GameType.Single,
        new List<IPlayer> { CreateHuman(); CreateBot() });
else if (gameType == GameType.PassAndPlay)
    return new Game(
        GameType.PassAndPlay,
        new List<IPlayer> { CreateHuman(); CreateHuman() });
else
    return new Game(
        GameType.Online,
        new List<IPlayer> { CreateHuman(); CreateOnlinePlayer() });

You can use Ninject for this, i use this approach in some projects that i worked, and is very simple, see the Ninject project site: https://github.com/ninject/Ninject/wiki/Contextual-Binding

About your comment my suggest is separe the games types in concrete classes that implements IGame interface`, see the example:

public interface IGame
{
    GameType Type { get; }
    ReadOnlyCollection<IPlayer> Players { get; }
}

public class GameSingle : IGame
{
    public GameSingle(List<IPlayer> players)
    {
        Players = players.AsReadOnly();
    }

    public GameType Type => GameType.Single;
    public ReadOnlyCollection<IPlayer> Players { get; }
}

public class GameOnline : IGame
{
    public GameOnline(List<IPlayer> players)
    {
        Players = players.AsReadOnly();
    }

    public GameType Type => GameType.Online;
    public ReadOnlyCollection<IPlayer> Players { get; }
}

public class GamePlayAndPass : IGame
{
    public GamePlayAndPass(List<IPlayer> players)
    {
        Players = players.AsReadOnly();
    }

    public GameType Type => GameType.PassAndPlay;
    public ReadOnlyCollection<IPlayer> Players { get; }
}

Now in the module of the ninject :

        Kernel.Bind<IPlayer>().To<Bott>().WhenInjectedExactlyInto<GameSingle>();
        Kernel.Bind<IPlayer>().To<OnlinePlayer>().WhenInjectedExactlyInto<GameOnline>();
        Kernel.Bind<IPlayer>().To<Human>().WhenInjectedExactlyInto<GamePlayAndPass>();
        Kernel.Bind<IPlayer>().To<Human>();

And then you just need to define when and where inject the IGame concrete class XD.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM