我正在使用Ninject来实例化一些带有构造函数arg的对象,例如:
class MyClass { public MyClass(string myArg) { this.myArg = myArg; } }
我需要这个类的实例数量直到运行时才知道,但我想要做的是确保myArg的每个变体产生一个不同的单例实例(因此要求两次相同的值会返回相同的实例,但是不同的args返回不同的实例).
有没有人知道一个好的,最好是内置的方式这样做?
我找到了一篇为Ninject How To Ensure One Instance per Variation of Activation Parameters的旧版本编写的文章,但希望有更新版本的更整洁的解决方案.
编辑
以下是我使用的内容,改编自Akim的答案如下:
private readonly ConcurrentBag<string> scopeParameters = new ConcurrentBag<string>(); internal object ParameterScope(IContext context,string parameterName) { var param = context.Parameters.First(p => p.Name.Equals(parameterName)); var paramValue = param.GetValue(context,context.Request.Target) as string; paramValue = string.Intern(paramValue); if (paramValue != null && !scopeParameters.Contains(paramValue)) { scopeParameters.Add(paramValue); } return paramValue; } public override void Load() { Bind<MyClass>() .ToSelf() .InScope(c => ParameterScope(c,"myArg")); Bind<IMyClassFactory>() .ToFactory(); }
解决方法
您可以通过使用IBindingNamedWithOrOnSyntax< T>提供自定义范围来实现需求行为.用于MyClass绑定的InScope(Func< IContext,object> scope)方法
Indicates that instances activated via the binding should be re-used
as long as the object returned by the provided callback remains alive
(that is,has not been garbage collected).
因此,您需要从Func< IContext,object>返回第一个构造函数参数的值. scope并确保garbage-collector不会收集它.
这是一个片段:
public class Module : NinjectModule { // stores string myArg to protect from CG ConcurrentBag<string> ParamSet = new ConcurrentBag<string>(); public override void Load() { Bind<MyClass>() .ToSelf() // custom scope .InScope((context) => { // get first constructor argument var param = context.Parameters.First().GetValue(context,context.Request.Target) as string; // retrieves system reference to string param = string.Intern(param); // protect value from CG if(param != null && ParamSet.Contains(param)) { // protect from GC ParamSet.Add(param); } // make Ninject to return same instance for this argument return param; }); } }