I understand the whole concept behind inversion of control, but struggle to figure out where an IoC container comes in and how it may help.
Here's an example. Let's say we have the following interfaces ...
public interface IWarrior
{
string Name { get; }
IWeapon Weapon { get; }
void EquipWeapon(IWeapon weapon);
void Attack(ITarget target);
void DoVictoryDance();
}
public interface IWeapon
{
int AttackPower { get; }
}
public interface ITarget
{
int Health { get; }
int ArmorValue { get; }
int ReceiveAttack(int damage);
}
A IWarrior base class ...
public abstract class BaseWarrior : IWarrior
{
private static readonly Random Random = new Random();
protected BaseWarrior(string name, IWeapon weapon)
{
Name = name;
Weapon = weapon;
}
public string Name { get; }
public IWeapon Weapon { get; private set; }
public virtual void Attack(ITarget target)
{
var attackValue = Random.Next(0, Weapon.AttackPower + 1);
var damageDone = target.ReceiveAttack(attackValue);
Console.WriteLine($"{Name} did {damageDone} to {target.GetType().Name}");
if (target.Health <= 0)
DoVictoryDance();
}
public virtual void EquipWeapon(IWeapon weapon)
{
Weapon = weapon;
Console.WriteLine($"{Name} equips {weapon.GetType().Name}");
}
public abstract void DoVictoryDance();
}
The concrete warriors types ...
public class Samurai : BaseWarrior
{
public Samurai(string name, IWeapon weapon) : base(name, weapon)
{
}
public override void DoVictoryDance()
{
Console.WriteLine($"{Name} dances on top of the corpses of his foes.");
}
}
public class ChuckNorris : BaseWarrior
{
public ChuckNorris() : base("Chuck Norris", null)
{
}
public override void Attack(ITarget target)
{
var targetName = target.GetType().Name;
Console.WriteLine($"Chuck Norris stares at {targetName}. {targetName} collapses on the floor, dead. {targetName} never saw Chuck Norris.");
DoVictoryDance();
}
public override void EquipWeapon(IWeapon weapon)
{
Console.WriteLine("Chuck Norris needs no weapons you fool!");
}
public override void DoVictoryDance()
{
Console.WriteLine("Chuck Norris doesn't dance. He stares at you until you do it for him.");
}
}
The following weapons...
public class Sword : IWeapon
{
public int AttackPower => 10;
}
public class CrossBow : IWeapon
{
public int AttackPower => 15;
}
And finally a basic enemy:
public class Bear : ITarget
{
public int Health { get; private set; } = 100;
public int ArmorValue => 2;
public int ReceiveAttack(int damage)
{
var damageTaken = damage - ArmorValue;
if (damageTaken > 0)
Health -= damageTaken;
return damageTaken;
}
}
It's clear to me what inversion of control here is. My main class needs not know the concrete type of IWarrior, IWarrior never knows the concrete type of IWeapon or ITarget.
So this allows me to do something like ...
ITarget target = new Bear();
IWarrior warrior = new ChuckNorris();
warrior.Attack(target);
or ...
ITarget target = new Bear()
IWarrior warrior = new Samurai("Ben", new Sword());
warrior.Attack(target);
And I can see how it would be easier to have a container that just stores my objects so I don't "lose track of them" (don't want a lot of swords or weapons flying around for example, also those could be singletons).
Examples I've seen of IoC containers show something similar to this:
IocContainer container = new IocContainer();
container.Bind<IWarrior>().To<Samurai>();
container.Bind<IWeapon>().To<Sword>();
container.Bind<ITarget>().To<Bear>();
and then doing something like...
ITarget target = container.Get<ITarget>();
IWarrior warrior = container.Get<IWarrior>();
warrior.Attack(target);
But now I'm basically saying that my IWarrior is always a Samurai, that my IWeapon is always a Sword and that my ITarget is always a Bear.
That's not really what I wanted! I want to be able to create different IWarrior types with different IWeapon combinations and attacking a multitude of ITargets!
Maybe I'm misunderstanding something basic about how an IoC container works, but I have seen a few videos about them (using multiple libraries) and they all appear to basically say when I want "something" implementing interface XX, find in your container an object of concrete type YY. If you don't have one there yet, create one, save it, and send it back to me.
Can someone explain what the advantages of an IoC container are, give real examples of how it works and how one can preserve choice (by not limiting a IWarrior to Samurai as above for example)?
Related
I'm trying to create unit tests for the GetOutOfJail method but I can't work out a way of getting to it as it private and apart from testing there is no need for it to be public. I can't change the signature of the LandedOnTile method as it inheriting a the abstract class Tile.
As you probably worked out, it is for a game of Monopoly I'm trying to make as a mini project.
public abstract class Tile
{
public abstract int Location { get;}
public abstract void LandedOnTile(Player player);
}
public class JailTile : Tile
{
public override int Location { get; }
Random dice = new Random();
public JailTile()
{
Location = 3;
}
public override void LandedOnTile(Player player)
{
if (player.inJail)
{
GetOutOfJail(player);
}
else
{
Console.WriteLine(player.name + " is just visiting jail");
}
}
private void GetOutOfJail(Player player)
{
int roll = dice.Next(1, 4);
int turnsInJail = player.timeInJail;
if (turnsInJail == 3)
{
player.inJail = false;
Console.WriteLine(player.name + " has spent 3 turns in jail and is now out");
player.timeInJail = 0;
}
else if (turnsInJail < 3 && roll > 2)
{
player.inJail = false;
Console.WriteLine(player.name + " has rolled a 3 and it out of jail");
player.timeInJail = 0;
}
else
{
Console.WriteLine(player.name + " has rolled a lower than a 3 and is in jail for another turn");
player.timeInJail++;
}
}
}
As mentioned by others, it shouldn't matter what the private method does from the perspective of the unit test. All you care about is that if you poke or prod the object in the right way, it ends up in the right state.
Here is how you could achieve that using interfaces and Moq.
Firstly, extract the interface that represents the properties and methods you require to perform the action. I have abstracted out your Console.WriteLine because it makes testing much easier (and even opens other opportunities for that code to be used in a non-console application). We don't actually need a "dice" per se. What we actually need is an object we can ask to Roll() and get an int. Players probably have their own business rules about them, so extracting to an IPlayer interface allows my tests of JailTile to ignore such things.
public interface ILogger
{
void LogMessage(string message);
}
public interface IDice
{
int Roll();
}
public interface IPlayer
{
string Name
{
get;
}
bool InJail
{
get;
set;
}
int TimeInJail
{
get;
set;
}
}
Secondly, here are the concrete implementations of a Dice and a ConsoleLogger. You would pass in these in your production code rather than the mocks that I use in the test cases
public class ConsoleLogger : ILogger
{
public void LogMessage(string message)
{
Console.WriteLine(message);
}
}
public class Dice : IDice
{
private readonly Random random = new Random();
public int Roll()
{
return this.random.Next(1, 6);
}
}
Thirdly, here are your Tile and JailTile classes slightly modified to use constructor injection
public abstract class Tile
{
protected readonly IDice Dice;
protected readonly ILogger Logger;
protected Tile(ILogger logger, IDice dice)
{
this.Logger = logger;
this.Dice = dice;
}
public abstract int Location
{
get;
}
public abstract void LandedOnTile(IPlayer player);
}
public class JailTile : Tile
{
public JailTile(ILogger logger, IDice dice): base (logger, dice)
{
}
public override int Location => 3;
public override void LandedOnTile(IPlayer player)
{
if (player.InJail)
{
this.GetOutOfJail(player);
}
else
{
this.Logger.LogMessage($"{player.Name} is just visiting jail");
}
}
private void GetOutOfJail(IPlayer player)
{
int roll = this.Dice.Roll();
int turnsInJail = player.TimeInJail;
if (turnsInJail == 3)
{
player.InJail = false;
this.Logger.LogMessage($"{player.Name} has spent 3 turns in jail and is now out");
player.TimeInJail = 0;
}
else if (turnsInJail < 3 && roll > 2)
{
player.InJail = false;
this.Logger.LogMessage($"{player.Name} has rolled a 3 and it out of jail");
player.TimeInJail = 0;
}
else
{
this.Logger.LogMessage($"{player.Name} has rolled a lower than a 3 and is in jail for another turn");
player.TimeInJail++;
}
}
}
Finally, here is a test case to prove that your jailTile.LandedOnTile() method causes the right changes to Player and logs the right message to console given a certain set of preconditions
[Test]
public void ShouldReleaseAfterThreeTurns()
{
// Arrange
Mock<ILogger> loggerMock = new Mock<ILogger>();
Mock<IDice> diceMock = new Mock<IDice>();
diceMock.Setup(s => s.Roll()).Returns(2);
Mock<IPlayer> playerMock = new Mock<IPlayer>();
playerMock.Setup(s => s.Name).Returns("Adam G");
playerMock.Setup(s => s.InJail).Returns(true);
playerMock.Setup(s => s.TimeInJail).Returns(3);
// Act
JailTile jailTile = new JailTile(loggerMock.Object, diceMock.Object);
jailTile.LandedOnTile(playerMock.Object);
// Assert
playerMock.VerifySet(v => v.InJail = false, Times.Once());
playerMock.VerifySet(v => v.TimeInJail = 0, Times.Once());
loggerMock.Verify(v => v.LogMessage("Adam G has spent 3 turns in jail and is now out"), Times.Once());
}
Now you probably want to think a bit more about the design, and whether it is really the tile's responsibility to be updating these properties, or whether it should call something on a jail object that can separately be tested, but this shows how you can use mocks to abstract calls to random etc out of your code to make it testable.
My brain is gonna to explode. :) So I would like to get help from you.
Please, think about my question like about just programmer puzzle. (Actually. perhaps it is very easy question for you, but not for me.)
It is needed to create array of objects. For example List where T is class. (I will describe Class T below). Also it is needed create “container” that will contain this array and some methods for work with this array. For example Add(), Remove(int IndexToRemove).
Class T must have field "Container", this way each elements of our array would be able to know where is it contained and has access its container's fields and methods. Notice, that in this case Class T should have type parameter. Indeed, it is not known beforehand which container's type is used.
Let us denote this class container as A and class element (class T) as AUnit.
Code:
class Program
{
static void Main(string[] args)
{
A a = new A();
a.Add();
a.Units[0].SomeField +=100;
Console.ReadKey();
}
}
class A
{
public List<AUnit> Units;
public A()//ctor
{
Units = new List<AUnit>();
}
public void Add()
{
this.Units.Add(new AUnit(this));
}
}
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
}
Public fields should be protected or private of course, but let think about this later.
You can ask “why we create public A Container field in AUnit”? We create field public string Name{get;private set;} (actually property but nevermind). And also we would like to be able to change value of this field for example method [Class AUnit] public bool Rename(string newName)();. The main idea of this method is changing Name field only that case if no one element in array (public List Units; ) has the same name like newName. But to achieve this, Rename method has to have access to all names that is currently used. And that is why we need Container field.
Code of extended version AUnit
class AUnit
{
public int SomeField;
public A Container;
public string Name { get; private set; }
public AUnit(A container)
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (AUnit unt in this.Container.Units)
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
Ok. If you still read it let's continue. Now we need to create Class B and class BUnit which will be very similar like Class A and Class Aunit. And finally the main question of this puzzle is HOW WE CAN DO IT? Of course, I can CopyPaste and bit modify A and AUnit and create this code.
class B
{
public List<BUnit> Units; //Only Type Changing
public B()//ctor Name changing...
{
Units = new List<BUnit>();//Only Type Changing
}
public void Add()
{
this.Units.Add(new BUnit(this));//Only Type Changing
}
}
class BUnit
{
public int SomeField;
public B Container;//Only Type Changing
public string Name { get; private set; }
public A a; //NEW FIELD IS ADDED (just one)
public BUnit(B container) //Ctor Name and arguments type changing
{
this.SomeField = 43;
this.Container = container;
this.Name = "Default";
this.a=new A(); //New ROW (just one)
}
public bool Rename(String newName)
{
Boolean res = true;
foreach (BUnit unt in this.Container.Units) //Only Type Changing
{
if (unt.Name == newName)
{
res = false;
break;
}
}
if (res) this.Name = String.Copy(newName);
return res;
}
}
And I can to use this classes this way.
static void Main(string[] args)
{
B b = new B();
b.Add();
b.Units[0].a.Add();
b.Units[0].a.Units[0].SomeField += 100;
bool res= b.Units[0].a.Units[0].Rename("1");
res = b.Units[0].a.Units[0].Rename("1");
Console.ReadKey();
}
This construction is can be used to create “non-homogeneous trees”.
Help, I need somebody help, just no anybody…. [The Beatles]
I created B and BUnit using CopyPaste.
But how it can be done using “macro-definitions” or “Generic”, inherit or anything else in elegant style? (C# language)
I think that there is no reason to describe all my unsuccessful attempts and subquestions. Already topic is too long. : )
Thanks a lot if you still read it and understand what I would like to ask.
You need to implement a base type, lets call it UnitBase, with all common functionality. I'd structure your code the following way:
Create an interface for your container, this way you can change implementation to more performant solutions without modifying the elements you will be adding to the container.
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
}
Following the idea stated in 1, why not make the search logic belong to the container? It makes much more sense, as it will mostly depend on how the container is implemented:
public interface IContainer
{
Q Add<Q>() where Q : UnitBase, new();
IEnumerable<UnitBase> Units { get; }
bool Contains(string name);
}
A specific implementation of IContainer could be the following:
public class Container : IContainer
{
public Container()
{
list = new List<UnitBase>();
}
private List<UnitBase> list;
public Q Add<Q>() where Q: UnitBase, new()
{
var newItem = Activator.CreateInstance<Q>();
newItem.SetContainer(this);
list.Add(newItem);
return newItem;
}
public IEnumerable<UnitBase> Units => list.Select(i => i);
public bool Contains(string name) =>
Units.Any(unit => unit.Name == name);
}
Create a base class for your AUnit and BUnit types condensing all common functionality:
public abstract class UnitBase
{
protected UnitBase()
{
}
public IContainer Container { get; private set; }
public int SomeField;
public string Name { get; private set; }
public void SetContainer(IContainer container)
{
Container = container;
}
public bool Rename(String newName)
{
if (Container.Contains(newName))
return false;
this.Name = newName; //No need to use String.Copy
return true;
}
}
Implement your concrete types:
public class BUnit : UnitBase
{
public int SpecificBProperty { get; private set; }
public BUnit()
{
}
}
Shortcomings of this approach? Well, the container must be of type <UnitBase>, I've removed the generic type because it really wasn't doing much in this particular case as it would be invariant in the generic type.
Also, keep in mind that nothing in the type system avoids the following:
myContainer.Add<BUnit>();
myContainer.Add<AUnit>();
If having two different types in the same container is not an option then this whole set up kind of crumbles down. This issue was present in the previous solution too so its not something new, I simply forgot to point it out.
InBetween , I am very thankful to you for your advices. Actually I can't say that I understood your answer in full, but using your ideas I have done what I want.
Looks like my variant works well. However I would like to hear your (and everyone) opinions about code described below. The main goal of this structure is creating non-homogeneous trees. So could you estimate it from this side.
First of all. We need to create interfaces for both classes. We describe there all "cross-used" functions.
public interface IUnit<T>
{
string Name { get;}
void SetContainer(T t);
bool Rename(String newName);
}
public interface IContainer
{
bool IsNameBusy(String newName);
int Count { get; }
}
Next. Create Base for Unit Classes for future inheritance. We will use in this inheritors methods from Container Base so we need generic properties and IUnit interface.
class UnitBase<T> : IUnit<T> where T : IContainer
Unfortunately I don't know yet how to solve the problem with Constructor parameters. That is why I use method
SetContainer(T container).
Code:UnitBase
class UnitBase<T> : IUnit<T> where T : IContainer
{
protected T Container;
public string Name { get; private set; }
public UnitBase()
{
this.Name = "Default";
}
public void SetContainer(T container)
{
this.Container = container;
}
public bool Rename(String newName)
{
bool res = Container.IsNameBusy(newName);
if (!res) this.Name = String.Copy(newName);
return !res;
}
}
Next. Create ContainerBase
ContainerBase should:
1) has IContainer interface.
2)has information about what it will contain:
... where U : IUnit<C>, new()
3)and .... has information about what itself is. This information we need to pass as parameter to SetContainer() method.
Code ContainerBase:
class ContainerBase<U, C> : IContainer //U - Unit Class. C-Container Class
where U : IUnit<C>, new()
where C : ContainerBase<U, C>
{
protected List<U> Units;
public U this[int index] { get { return Units[index]; } }
public ContainerBase()//ctor
{
this.Units = new List<U>();
}
public void Add()
{
this.Units.Add(new U());
this.Units.Last().SetContainer(((C)this));//may be a bit strange but actualy this will have the same type as <C>
}
public bool IsNameBusy(String newName)
{
bool res = false;
foreach (var unt in this.Units)
{
if (unt.Name == newName)
{
res = true;
break;
}
}
return res;
}
public int Count { get { return this.Units.Count; } }
}
Cast ((TContainer)(this)) may be is a bit strange. But using ContainerBase we always should use NewInheritorContainer. So this cast is just do nothing…looks like...
Finally. This classes can be used like in this example.
class SheetContainer : ContainerBase<SheetUnit,SheetContainer> {public SheetContainer(){}}
class SheetUnit : UnitBase<SheetContainer>
{
public CellContainer Cells;
public PictureContainer Pictures;
public SheetUnit()
{
this.Cells = new CellContainer();
this.Pictures = new PictureContainer();
}
}
class CellContainer : ContainerBase<CellUnit, CellContainer> { public CellContainer() { } }
class CellUnit : UnitBase<CellContainer>
{
public string ValuePr;//Private Field
private const string ValuePrDefault = "Default";
public string Value//Property for Value
{
//All below are Just For Example.
get
{
return this.ValuePr;
}
set
{
if (String.IsNullOrEmpty(value))
{
this.ValuePr = ValuePrDefault;
}
else
{
this.ValuePr = String.Copy(value);
}
}
}
public CellUnit()
{
this.ValuePr = ValuePrDefault;
}
}
class PictureContainer : ContainerBase<PictureUnit, PictureContainer> { public PictureContainer() { } }
class PictureUnit : UnitBase<PictureContainer>
{
public int[,] Pixels{get;private set;}
public PictureUnit()
{
this.Pixels=new int[,]{{10,20,30},{11,12,13}};
}
public int GetSizeX()
{
return this.Pixels.GetLength(1);
}
public int GetSizeY()
{
return this.Pixels.GetLength(0);
}
public bool LoadFromFile(string path)
{
return false;
}
}
static void Main(string[] args)
{
SheetContainer Sheets = new SheetContainer();
Sheets.Add();
Sheets.Add();
Sheets.Add();
Sheets[0].Pictures.Add();
Sheets[1].Cells.Add();
Sheets[2].Pictures.Add();
Sheets[2].Cells.Add();
Sheets[2].Cells[0].Value = "FirstTest";
bool res= Sheets[0].Rename("First");//res=true
res=Sheets[2].Rename("First");//res =false
int res2 = Sheets.Count;
res2 = Sheets[2].Pictures[0].Pixels[1, 2];//13
res2 = Sheets[2].Pictures.Count;//1
res2 = Sheets[1].Pictures.Count;//0
res2 = Sheets[0].Pictures[0].GetSizeX();//3
Console.ReadKey();
}
Looks like it works like I want. But I didn’t test it full.
Let me say Thank you again, InBetween.
I'm building very simple board game (just to learn some new stuff). It will be cross-platform (written using Xamarin). I've already written the core of the game, but I'm not sure (still) whether should I use constructor injection or IoC resolve. Right now I use IoC.Resolve and then pass through parameter.
Here is my code. I have Game that has 2 dependencies and type. I have factories to create Games and Players:
Abc.MyGame.Domain
Interfaces
public interface IGame
{
GameType GameType { get; }
IGameBoard GameBoard { get; }
List<IPlayer> Players { get; }
// Other stuff...
}
public interface IGameBoard
{
//board stuff...
}
public interface IPlayer
{
int PlayerId { get; set; }
PlayerType PlayerType { get; set; }
}
Factory interfaces
public interface IGameFactory
{
IGame CreateGame(GameType type, IGameBoard board);
}
public interface IPlayerFactory
{
IPlayer CreatePlayer(PlayerType type, int id);
}
Factories
public class GameFactory : IGameFactory
{
public IGame CreateGame(GameType type, IGameBoard board)
{
switch (type)
{
case GameType.SinglePlayer:
return new MyGame(type, board,
new List<IPlayer> { CreateHuman(1), CreateBot(2) });
case GameType.TwoPlayers:
return new MyGame(type, board,
new List<IPlayer> { CreateHuman(1), CreateHuman(2) });
case GameType.Online:
return new MyGame(type, board,
new List<IPlayer> { CreateHuman(1), CreateOnlinePlayer(2) });
}
return null;
}
}
Then, there is an API. Used by UI:
Abc.MyGame.API
public class GameAPI
{
public IGame CurrentGame { get; set; }
public IGame CreateGame(IGameFactory gameFactory, GameType type, IBoard board)
{
CurrentGame = gameFactory.CreateGame(type, board);
return CurrentGame;
}
// Other stuff, like make move etc...
}
... and my UI:
Abc.MyGame.UI.WinForms
public partial class Form1 : Form
{
private GameAPI api = new GameAPI();
IKernel kernel = new StandardKernel();
public Form1()
{
InitializeComponent();
// Load all dependencies
var modules = new List<INinjectModule> { new GameModule() };
kernel.Load(modules);
}
private void buttonStartGame(object sender, EventArgs e)
{
IGameBoard board = kernel.Get<IGameBoard>(
new ConstructorArgument("width", 7),
new ConstructorArgument("height", 6)
);
api.CreateGame(kernel.Get<IGameFactory>(), GameType.TwoPlayers, board);
}
}
I need to IGameBoard in my IGame. ONLY there. I need to inject board and players to IGame.
Here is my problem/question:
Do I really need to resolve IGameBoard at the very "front" of my program? I resolve it in UI, when somebody click "Start Game" button. And then I pass this board through API, then I pass it to GameFactory, then I pass it to Game constructor (finally!). Is it a bad practice to create (or resolve) IPlayerFactory and IGameBoard inside GameFactory? API.CreateGame will have only type parameter in that case? I mean for specific GameFactory there is only one board (evey time the same), so I'm not sure I need to create board at the very beginning...
EDIT:
MyGame constructor:
public class MyGame : IGame
{
public IBoard Board { get; }
public GameType Type { get; }
public List<IPlayer> Players { get; }
public MyGame(GameType type, IBoard board, List<IPlayer> players)
{
Type = type;
Board = board;
Players = players;
}
//...
}
Do I really need to resolve IGameBoard at the very "front" of my program?
Yes, dependencies need to be resolved at entry points and at the start of lifetime scopes (if any) in your application. Often, this is abstracted (like in ASP.NET MVC), so you never have to call kernel.Get<> (or any other container.Resolve<>) yourself. In WinForms there is no such mechanism, so you have to resolve the dependencies yourself, preferably only the root dependency like this:
public static class Program
{
private static void Main()
{
var kernel = new StandardKernel();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(kernel.Get<Form1>());
}
}
By putting the right dependencies on your main form (probably including a factory in your case for the games), you should not need any more kernel.Get<> in your application.
I have a wcf service application and I have just implemented ninject library. In ninject web site there is following example:
public class Samurai {
public IWeapon Weapon { get; private set; }
public Samurai(IWeapon weapon)
{
this.Weapon = weapon;
}
}
public class WarriorModule : NinjectModule
{
public override void Load()
{
this.Bind<IWeapon>().To<Sword>();
}
}
I have classes like this. But problem is how can I create instance of Samurai class? It's constructor have parameter (IWeapon), but the parameter is binded Sword or different class. When I want to create instance of Samurai class, compiler expects IWeapon type parameter. In my module class (like WarriorModule) I have already defined it's binding. How can I pass parameter (or some different way) to Samurai class's constuctor?
Try this
class Program
{
static void Main(string[] args)
{
IKernel kernel = new StandardKernel(new WarriorModule());
var samurai = kernel.Get<ISamurai>();
}
}
public interface ISamurai
{
}
public class Samurai : ISamurai
{
public IWeapon Weapon { get; private set; }
public Samurai(IWeapon weapon)
{
this.Weapon = weapon;
}
}
public interface IWeapon
{
}
public class Sword : IWeapon
{
}
public class WarriorModule : NinjectModule
{
public override void Load()
{
this.Bind<ISamurai>().To<Samurai>();
this.Bind<IWeapon>().To<Sword>();
}
}
I just figured out how to do is. There is no need to create ISamurai interface. In Warriormodule:
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWeapon>().To<Sword>();
Bind<Samurai>().ToSelf();
}
}
To create Samurai instance:
var samurai = kernel.Get<Samurai>();
I've used Ninject with MVC3 for automagic inject of constructor arguments. It worked great.
How do you do something similar with non-MVC code.
For example:
public class Ninja
{
private readonly IWeapon _weapon;
public Ninja(IWeapon weapon)
{
_weapon = weapon;
}
public void Strike()
{
_weapon.Strike();
}
}
public class MyProgram
{
public void DoStuff()
{
var Ninja = new Ninja(); // I'm wanting Ninject to call the parameterized Ninja constructor
ninja.Strike();
}
}
How would I alter the code to get it to work?
public interface IWeapon
{
void Strike();
}
public class Sword : IWeapon
{
public void Strike()
{
Console.WriteLine("black ninja strike");
}
}
public class Ninja
{
private readonly IWeapon _weapon;
public Ninja(IWeapon weapon)
{
_weapon = weapon;
}
public void Strike()
{
_weapon.Strike();
}
}
public class WarriorModule : NinjectModule
{
public override void Load()
{
Bind<IWeapon>().To<Sword>();
}
}
class Program
{
static void Main()
{
var kernel = new StandardKernel(new WarriorModule());
var ninja = kernel.Get<Ninja>();
ninja.Strike();
}
}
Wouldn't it just be:
var ninja = Kernel.Get<Ninja>();
You obviously have to resolve the dependency though Ninject.
You need to have an instance of StandardKernel let's call it kernel and then use kernel.Get<Ninja>(). This works since Ninja is non abstract, so it is considered bound to itself. Obviously some concrete types needs to be bound to IWeapon to allow NInject to create Ninja.