C# IoC:实现条件注入
C# IoC: Implementing conditional injection
我想创建一个简单的游戏并使用其中一个 IoC 容器。每个游戏都有玩家,所以我想把他们注入Game
class。问题是,可能有不同类型的玩家。第一个玩家将始终是人类(设备所有者;)),但他的对手:人类(游戏和传球)、机器人或在线(人类,但通过互联网游戏)。
这是代码。有不同的玩家:
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; }
}
和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; }
}
如您所见,我在游戏容器中注入了玩家列表。这是我的问题:
如果类型不同 GameType
,我如何解决 List<IPlayer>
?
if GameType = 单人游戏 -> 注入人类和机器人
if GameType = Pass and play -> Inject Human and Human
if GameType = Online game -> Inject Human and OnlinePlayer
你可以使用 Ninject,我在我工作的一些项目中使用了这种方法,
非常简单,请参阅 Ninject 项目站点:https://github.com/ninject/Ninject/wiki/Contextual-Binding
关于您的评论,我的建议是将实现 IGame
接口的具体 classes 中的游戏类型分开,参见示例:
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; }
}
现在在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>();
然后你只需要定义何时何地注入 IGame 具体 class XD。
没有理由让它变得比它必须的更复杂。你可以这样写 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() });
我想创建一个简单的游戏并使用其中一个 IoC 容器。每个游戏都有玩家,所以我想把他们注入Game
class。问题是,可能有不同类型的玩家。第一个玩家将始终是人类(设备所有者;)),但他的对手:人类(游戏和传球)、机器人或在线(人类,但通过互联网游戏)。
这是代码。有不同的玩家:
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; }
}
和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; }
}
如您所见,我在游戏容器中注入了玩家列表。这是我的问题:
如果类型不同 GameType
,我如何解决 List<IPlayer>
?
if GameType = 单人游戏 -> 注入人类和机器人
if GameType = Pass and play -> Inject Human and Human
if GameType = Online game -> Inject Human and OnlinePlayer
你可以使用 Ninject,我在我工作的一些项目中使用了这种方法, 非常简单,请参阅 Ninject 项目站点:https://github.com/ninject/Ninject/wiki/Contextual-Binding
关于您的评论,我的建议是将实现 IGame
接口的具体 classes 中的游戏类型分开,参见示例:
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; }
}
现在在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>();
然后你只需要定义何时何地注入 IGame 具体 class XD。
没有理由让它变得比它必须的更复杂。你可以这样写 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() });