背景
我有一个实现IEnvironment的'root'实例。在我的应用程序中,可能有多个([1..N])IE环境。每个环境都包含一堆对象,其中一些包含ninject工厂,另一些是单例(Bind< ...>()。To< ...> .InSingletonScope())。
我使用单个IEnvironment实现了一个简单使用默认绑定的原型,所有依赖对象都传入了它们的单个实例,工厂是使用Ninject ToFactory()扩展创建的。这有效。
我几乎完全使用ctor-injection,我宁愿保持这种方式。
目标
如何为每个环境创建不同的上下文?也就是说,IEnvironment中的每个实例应该得到相同的ISingleton,并且这些对象中的所有工厂都应该将这个单例传递给它的创建对象,但每个IE环境都应该有一个不同的ISingleton实例。
问题
我已阅读有关Ninject的Contextual Binding和Context Preservation的文章。但我不明白如何将其映射到我的问题。据我所知,我不能使用命名绑定或属性,因为我可能有N个IE环境,并且该数字可能依赖于从外部传递的一些信息。
那么 - 我如何设置Ninject或我的应用程序以使其工作?我正在寻找一个答案来解释如何解决这个问题的概念方法。
答案 0 :(得分:3)
如果您符合以下条件,则可以使用.InNamedScope(...)
:
ISingleton
不在环境之外使用(即,只注入环境或注入环境的依赖关系,并为每个环境实例化)。 备注:如果要解决环境中工厂使用ISingleton
的新对象,则需要使用上下文保留扩展。
this.Bind<IEnvironment>().To<Environment>().DefinesNamedScope("SomeName");
this.Bind<ISingleton>().To<Singleton>.InNamedScope("SomeName")
- &GT;确保在环境请求范围中仅创建一个Singleton实例。
当然,如果能够更好地满足您的需求,您也可以创建自己的InScope(...)
。
另一个替代是使用继承的构造函数参数(如果需要在以后创建实例时保留上下文,请再次使用上下文保存):
IEnvironment CreateEnvironment()
{
var singleton = IResolutionRoot.Get<ISingleton>();
return IResolutionRoot.Get<IEnvironment>(new ConstructorArgument("singleton", singleton, true);
}
提示:构造函数参数采用参数shouldInherit,在这种情况下应为true。 我还建议使用与ConstructorArgument不同的参数。使用ConstructorArgument时,参数名称需要匹配(即当某个类想要注入ISingleton时,它需要有一个名为“singleton”的ctor参数)。 这将是另一种选择:
public class TypedConstructorArgument:ITypedParameter,IConstructorArgument { public TypedConstructorArgument(Type argumentType,object argumentValue) :this(argumentType,argumentValue,false) { }
public TypedConstructorArgument(Type argumentType, object argumentValue, bool shouldInherit)
{
Ensure.ArgumentAssignableFrom(argumentType, argumentValue, "argumentValue");
this.ArgumentType = argumentType;
this.ArgumentValue = argumentValue;
this.ShouldInherit = shouldInherit;
this.Name = argumentType.FullName;
}
public virtual string Name { get; private set; }
public virtual bool ShouldInherit { get; private set; }
public virtual Type ArgumentType { get; private set; }
public virtual object ArgumentValue { get; private set; }
public object GetValue(IContext context, ITarget target)
{
return this.ArgumentValue;
}
public bool AppliesToTarget(IContext context, ITarget target)
{
return this.MatchesType(target.Type);
}
public override bool Equals(object obj)
{
var other = obj as IParameter;
return other != null && this.Equals(other);
}
public override int GetHashCode()
{
return this.GetType().GetHashCode() ^ this.Name.GetHashCode();
}
public bool Equals(IParameter other)
{
return other.GetType() == this.GetType() && other.Name.Equals(this.Name);
}
public bool MatchesType(Type type)
{
return this.ArgumentType == type;
}
}