如何在Ninject中使用“复合设计模式”
validation规则合同:
public interface IValidationRule { bool IsValid(); }
具体validation规则:
public class MyClass : IValidationRule { public bool IsValid() { return true; } }
综合:
public class ValidationRuleComposite : IValidationRule { private readonly IEnumerable _validationRules; public ValidationRuleComposite(IEnumerable validationRules) { _validationRules = validationRules; } public bool IsValid() { return _validationRules.All(x => x.IsValid()); } }
当我向IValidationRule
询问IValidationRule
我想得到ValidationRuleComposite
。 如果我向容器询问IValidationRule
列表,我想获得除ValidationRuleComposite
之外的所有IValidationRule
实现。
如何使用Ninject实现这一目标?
首先,您要设置将注入复合的IEnumerable
// Bind all the individual rules for injection into the composite kernel.Bind().To().WhenInjectedInto(); kernel.Bind().To().WhenInjectedInto();
或者您也可以使用约定绑定扩展相当容易地设置IEnumerable,这样您就不必为每个单独的具体规则添加单独的绑定。 只需确保为复合类添加Exlcuding子句,如下所示:
using Ninject.Extensions.Conventions; // Bind all the non-composite IValidationRules for injection into ValidationRuleComposite kernel.Bind(x => x.FromAssemblyContaining(typeof(ValidationRuleComposite)) .SelectAllClasses() .InheritedFrom() .Excluding() .BindAllInterfaces() .Configure(c => c.WhenInjectedInto ()));
在我的例子中,复合材料和其余的混凝土在同一个组件中,但显然你可以改变你的约定绑定,如果它们在其他地方。
最后,我们需要设置绑定,以便在其他任何地方请求IValidationRule,Ninject提供复合。 似乎没有一个优雅的方法存在,所以我写了自己的When子句,以避免周期性注入:
// Now bind the composite to the interface for everywhere except itself kernel.Bind().To() .When(x => x.Target == null || x.Target.Member.ReflectedType != typeof(ValidationRuleComposite));
在这里,我假设您需要所有validation规则而不是它们的部分列表,根据更通用的模式。 我会略微更改Composition类,以便您可以执行
kernel.Get()
和a
kernel.GetAll()
一个简单的例子如下。 接口
public interface IValidationRule { bool IsValid(); } public interface IValidationRuleComposite : IValidationRule { void ValidationRuleCompose(List validationRules); }
和规则
public class MyClass1 : IValidationRule { public bool IsValid() { Debug.WriteLine("Valid 1"); return true; } } public class MyClass2 : IValidationRule { public bool IsValid() { Debug.WriteLine("Valid 2"); return false; } }
复合规则
public class ValidationRuleComposite : IValidationRuleComposite { private List _validationRules; public void ValidationRuleCompose(List validationRules) { _validationRules = _validationRules.Union(validationRules).ToList(); } public ValidationRuleComposite() { _validationRules = new List (); } public bool IsValid() { Debug.WriteLine("Composite Valid"); return _validationRules.All(x => x.IsValid()); } }
和一个主要的
StandardKernel kernel = new StandardKernel(); kernel.Bind().To(); kernel.Bind().To(); kernel.Bind().To(); IValidationRuleComposite try1 = kernel.Get(); IEnumerable rules = kernel.GetAll (); foreach(IValidationRule trycomp in rules) { Debug.WriteLine("trycomp: " + trycomp.GetType().ToString()); trycomp.IsValid(); }; try1.ValidationRuleCompose(rules.ToList()); Console.WriteLine("{0}",try1.IsValid()); Debug.WriteLine("try1: " + try1.GetType().ToString());
编辑
等效替代,保留您的复合构造函数
public interface IValidationRuleCompositeConstr : IValidationRule { } public class ValidationRuleCompositeOriginal : IValidationRuleCompositeConstr { private readonly IEnumerable _validationRules; public ValidationRuleCompositeOriginal(IEnumerable validationRules) { _validationRules = validationRules; } public bool IsValid() { return _validationRules.All(x => x.IsValid()); } }
与相应的用法:
StandardKernel kernel = new StandardKernel(); kernel.Bind().To(); kernel.Bind().To(); kernel.Bind().To(); IEnumerable rules = kernel.GetAll (); Ninject.Parameters.ConstructorArgument therules = new Ninject.Parameters.ConstructorArgument("therules", rules); IValidationRuleCompositeConstr try2 = kernel.Get(therules); Debug.WriteLine("Second Class"); Debug.WriteLine (string.Format("{0}",try2.IsValid()));
我不知道如何使用Ninject直接执行此操作,但您可以使用Ninject创建一个类,然后创建validation规则。
public class ValidationRuleFactory : IValidationRuleFactory { public IValidationRule CreateComposite() { var rules = CreateRules(); return new ValidationRuleComposite(rules); } private IEnumerable CreateRules() { //return all other rules here. //I would hard code them and add new ones here as they are created. //If you don't want to do that you could use reflection. } }
因为这个类没有任何状态,你可以用单例范围创建它。
kernel.Bind().To().InSingletonScope();
然后注入此类并使用它来创建复合
public class MyClass() { private readonly IValidationRuleFactory _validationRuleFactory; public MyClass(IValidationRuleFactory validationRuleFactory) { _validationRuleFactory = validationRuleFactory; } public bool CheckValid() { var composite = _validationRuleFactory.CreateComposite(); return composite.IsValid(); } }
你在Ninject中连接你的ValidationRule的具体实例,就像这样。
this.Kernel.Bind().ToSelf(); this.Kernel.Bind().ToSelf(); this.Kernel.Bind().To() .WithConstructorArgument("validationRules", new IValidationRule[] { this.Kernel.Get(), this.Kernel.Get() });
现在,只要您的服务在其构造函数中使用IValidationRule
,您将获得ValidationRuleComposite
具体类型,同时注入ValidationRule1
和ValidationRule2
。
据我所知,Ninject在注入多个相同类型的实例时效果不佳。 在这种情况下,我们避免这样做,因此解析IValidationRule
始终会导致复合类型。
但是,您可以使用Reflection自动查找所有类型构建自己的扫描约定,排除名称中带有后缀“Composite”的任何类型,然后遍历类型以首先将它们绑定到self,然后创建实例数组注入。 看看这个自定义扫描实现的示例 及其用法 。
在Soldarnal的帮助下,我得出了以下解决方案:
public static class KernelExtensions { public static void BindComposite(this StandardKernel container) where TComposite : TCompositeElement { container.Bind(x => x.FromAssemblyContaining(typeof(TComposite)) .SelectAllClasses() .InheritedFrom() .Excluding() .BindAllInterfaces() .Configure(c => c.WhenInjectedInto ())); container.Bind().To() .When(IsNotCompositeTarget ); } private static bool IsNotCompositeTarget (IRequest x) { if (x.Target == null) return true; return x.Target.Member.ReflectedType != typeof(TComposite); } }
用法:
上述就是C#学习教程:如何在Ninject中使用“复合设计模式”分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!
var container = new StandardKernel(); container.BindComposite();
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/cdevelopment/992091.html