一个武士拿着剑,一个拿着匕首
本文关键字:一个 武士 | 更新日期: 2023-09-27 17:58:08
感谢您的关注。我对Ninject有点陌生,到目前为止我很喜欢它。我得到了在调试模式下绑定一个东西,在发布模式下绑定另一个东西的部分。这些是全局绑定,您必须使用Ninjects示例代码声明每个武士都将拥有一把剑或匕首。不是非此即彼,而是非此即合。
我该怎么做呢?我可以让一个武士带着剑,另一个武士拿着匕首,如果他们愿意的话,他们甚至可以交换武器。除了创建一堆具有不同绑定模块的内核之外,还有其他方法吗?
以下是来自Ninject的示例代码。如果你把它放在控制台应用程序中,它应该运行:
using System;
using Ninject;
namespace NinjectConsole
{
class Program
{
//here is where we have to choose which weapon ever samurai must use...
public class BindModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
//Bind<IWeapon>().To<Sword>();
Bind<IWeapon>().To<Shuriken>();
}
}
class Shuriken : IWeapon
{
public void Hit(string target)
{
Console.WriteLine("Pierced {0}'s armor", target);
}
}
class Sword : IWeapon
{
public void Hit(string target)
{
Console.WriteLine("Chopped {0} clean in half", target);
}
}
interface IWeapon
{
void Hit(string target);
}
class Samurai
{
readonly IWeapon weapon;
[Inject]
public Samurai(IWeapon weapon)
{
if (weapon == null)
throw new ArgumentNullException("weapon");
this.weapon = weapon;
}
public void Attack(string target)
{
this.weapon.Hit(target);
}
}
static void Main(string[] args)
{
//here is where we bind...
Ninject.IKernel kernel = new StandardKernel(new BindModule());
var samurai = kernel.Get<Samurai>();
samurai.Attack("your enemy");
//here is I would like to do, but with DI and no local newing up...
var warrior1 = new Samurai(new Shuriken());
var warrior2 = new Samurai(new Sword());
warrior1.Attack("the evildoers");
warrior2.Attack("the evildoers");
Console.ReadKey();
}
}
}
编辑
感谢您的重播和建议
我想好了如何得到我想要的东西。好吧,这就是我所做的:
- 将默认/初始绑定设置为最弱的武器。有点像一个新手
- 增加了另一件武器(匕首)
- 扩展IWeapon以包括武器命中点值来对武器值进行评级
- 扩展了武士,包括一个增加和减少武器的方法,这样武士可以获得或失去武器
- 修改了攻击方法以使用最佳武器
- 修改程序以利用添加的功能
- TODO:添加try/catch和null检查
创建一个名为NinjectConsole的控制台项目,安装Ninject,您应该可以直接将其放入并运行它
这是新代码:
using System;
using System.Collections.Generic;
using System.Linq;
using Ninject;
namespace NinjectConsole
{
class Program
{
public class BindModule : Ninject.Modules.NinjectModule
{
// default bind to weakest weapon
public override void Load()
{
Bind<IWeapon>().To<Dagger>();
}
}
class Dagger : IWeapon
{
public int WeaponHitPoints { get { return 5; } }
public string Hit(string target)
{
return String.Format("Stab {0} to death", target);
}
}
class Shuriken : IWeapon
{
public int WeaponHitPoints { get { return 9; } }
public string Hit(string target)
{
return String.Format("Pierced {0}'s armor", target);
}
}
class Sword : IWeapon
{
public int WeaponHitPoints { get { return 11; } }
public string Hit(string target)
{
return string.Format("Chopped {0} clean in half", target);
}
}
interface IWeapon
{
int WeaponHitPoints { get; }
string Hit(string target);
}
private class Samurai
{
private IEnumerable<IWeapon> _allWeapons;
public Samurai(IWeapon[] allWeapons)
{
if (!allWeapons.Any())
throw new ArgumentException("Samurai");
_allWeapons = allWeapons;
}
public void AddWeapon(IWeapon weapon)
{ //TODO: check for nulls...
_allWeapons = _allWeapons.Concat(new[] { weapon });
}
public void DropWeapon(IWeapon weapon)
{ //TODO: check for nulls...
Console.WriteLine("A Samurai got rid of a " + weapon.WeaponName);
_allWeapons = _allWeapons.Where(x => x.WeaponName != weapon.WeaponName);
}
public void Attack(string target)
{
int points = 0;
try
{
points = _allWeapons.Max(x => x.WeaponHitPoints);
}
catch ()
{
Console.WriteLine("You just punched " + target + " on the nose!");
}
var attackWeapon = _allWeapons.FirstOrDefault(i => i.WeaponHitPoints == points);
//TODO: check for nulls...
Console.WriteLine(attackWeapon.Hit(target));
}
}
static void Main(string[] args)
{
Ninject.IKernel kernel = new StandardKernel(new BindModule());
var samurai1 = kernel.Get<Samurai>();
var samurai2 = kernel.Get<Samurai>();
Console.WriteLine("Samurai #1");
samurai1.Attack("your enemy");
samurai2.AddWeapon(new Shuriken());
Console.WriteLine("'nSamurai #2 selects best weapon for attack");
samurai2.Attack("your enemy");
Console.WriteLine("'nSamurai #1 gets new weapon!");
samurai1.AddWeapon(new Sword());
Console.WriteLine("Samurai #1 selects best weapon for attack");
samurai1.Attack("your enemy");
Console.ReadKey();
}
}
}
一般来说,除非您指定一些条件,否则您无法使用IOC容器实现这一点,这些条件必须满足才能选择正确的实现(武器)。容器需要知道在当前情况下选择哪种实现。
我建议,你正在寻找某种上下文绑定。
Ninject中有很多条件绑定方法(请参阅上面的链接)。我选择了命名绑定,因为它是一个非常简单的例子
命名绑定
依赖项是根据配置的名称解析的
kernel.Bind<Samurai>().ToSelf().Named("SwordMaster");
kernel.Bind<Samurai>().ToSelf().Named("ShurikenMaster");
kernel.Bind<IWeapon>().To<Sword>().WhenParentNamed("SwordMaster");
kernel.Bind<IWeapon>().To<Shuriken>().WhenParentNamed("ShurikenMaster");
warrior1 = kernel.Get<Samurai>("SwordMaster");
warrior2 = kernel.Get<Samurai>("ShurikenMaster");
多次注射
如果您希望Samurai
能够处理多个武器,您可以为IWeapon
声明多个绑定,这些绑定可以作为集合注入到Samurai
中。
public Samurai(IEnumerable<IWeapon> weapons)
{
this.AllMyWeapons = weapons;
}
不幸的是,尽管Ninject文档使理解容器的语法变得容易,但它也可能给人一种错误的印象,即何时应该使用IoC容器。
我们的想法是,您的服务是从IoC容器注册和解析的,但Samurai
并不是真正的服务,它是域对象。这些应该由(例如)SamuraiFactory
构建(现在有一个可怕的想法…)
解析服务时,预计您只需要在初始化期间注入组件一次。这是唯一一次使用IoC容器——理想情况下应该调用。Resolve()只需一次,即可启动依赖关系网络。当你有了composition根时,你就有了程序的入口点——从那时起,你就不会引用IoC容器,你的程序也会正常执行。