Contextual Binding
Contextual Binding,上下文绑定,即根据不同的环境使用不同接口的实例。
先说下为什么要使用上下文绑定。
希望大家能学到更多的东西,多想想为什么,这点会对你产生非常大的影响。
通常我们会有这么几种需求:
1 Multiple bindings,多重绑定,用于多重的注入。
多重绑定,我们的对象其实是一组接口的集合。用代码的方式就是这样,程序员最喜欢的~~~
class Warrior { readonly IEnumerable<IWeapon> _weapons; public Warrior( IEnumerable<IWeapon> weapons) { _weapons=weapons; } public void Attack(string victim) { foreach(var weapon in _weapons) Console.WriteLine(weapon.Hit(victim)); } }
2 Simple constrained resolution: Named bindings,简单约束,命名绑定
命名绑定:最简单也是最常用的方式,通过不同的条件进行绑定。代码就是 :
Bind<IWeapon>().To<Shuriken>().Named("Strong"); Bind<IWeapon>().To<Dagger>().Named("Weak");
实现的时候:
class WeakAttack { readonly IWeapon _weapon; public([Named("Weak")] IWeapon weakWeapon) _weapon = weakWeapon; } public void Attack(string victim){ Console.WriteLine(_weapon.Hit(victim)); } }
还有一种实现的方式:
kernel.Get<IWeapon>("Weak"); //服务定位,这是一种反模式
有兴趣的可以看看这篇文章:
还有几种比较难的,上代码,喜欢研究的可以深入 地址:上下文绑定
// will work just as well without this line, but it's more correct and important for IntelliSense etc. [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] public class Swimmer : ConstraintAttribute { public bool Matches(IBindingMetadata metadata) { return metadata.Has("CanSwim") && metadata.Get<bool>("CanSwim"); } } class WarriorsModule : Ninject.Modules.NinjectModule { public override void Load() { Bind<IWarrior>().To<Ninja>(); Bind<IWarrior>().To<Samurai>().WithMetadata("CanSwim", false); Bind<IWarrior>().To<SpecialNinja>().WithMetadata("CanSwim", true); } } class AmphibiousAttack { public AmphibiousAttack([Swimmer]IWarrior warrior) { Assert.IsType<SpecialNinja>(warrior); } }
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = true, Inherited = true)] public class NonSwimmer : ConstraintAttribute { public override bool Matches(IBindingMetadata metadata) { return metadata.Has("CanSwim") && !metadata.Get<bool>("CanSwim"); } } class OnLandAttack { public OnLandAttack([NonSwimmer]IWarrior warrior) { Assert.IsType<Samurai>(warrior); } }
class JustAttack { // Note: This will fail because we have three matching bindings. public JustAttack(IWarrior warrior) { } }
Bind<IWarrior>().To<Samurai>().WhenInjectedInto(typeof(OnLandAttack)); Bind<IWarrior>().To<SpecialNinja>().WhenInjectedInto(typeof(AmphibiousAttack));
class SwimmerNeeded : Attribute{} class ClimberNeeded : Attribute{}
class WarriorsModule : Ninject.Modules.NinjectModule { public override void Load() { Bind<IWarrior>().To<Ninja>(); Bind<IWarrior>().To<Samurai>().WhenClassHas<ClimberNeeded>(); Bind<IWarrior>().To<Samurai>().WhenTargetHas<ClimberNeeded>(); Bind<IWarrior>().To<SpecialNinja>().WhenMemberHas<SwimmerNeeded>(); } }
class MultiAttack { public MultiAttack([ClimberNeeded] IWarrior MountainWarrior) { } [Inject, SwimmerNeeded] IWarrior OffShoreWarrior { get; set; } [Inject] IWarrior AnyOldWarrior {get;set;} } [ClimberNeeded] class MountainousAttack { [Inject, SwimmerNeeded] IWarrior HighlandLakeSwimmer { get; set; } [Inject] IWarrior StandardMountainWarrior { get; set; } }
Bind<IWarrior>().To<Samurai>().When(request => request.Target.Member.Name.StartsWith("Climbing")); Bind<IWarrior>().To<Samurai>().When(request => request.Target.Type.Namespace.StartsWith("Samurais.Climbing"));
class ClassThatLogs { ILog _log = LogFactory.CreateLog(typeof(ClassThatLogs)); // Sometimes one sees reflection based approaches too, which have efficiency issues }
Bind<ILog>().ToMethod( context => LogFactory.CreateLog( context.Request.Target.Type ) );
class ClassThatLogs { readonly ILog _log; public ClassThatLogs(ILog log){ _log = log; } }