Ninject Memoize Instances in Singleton

I use Ninject to instantiate some objects with the passed constructor argument, for example:

class MyClass
{
    public MyClass(string myArg)
    {
        this.myArg = myArg;
    }
}

The number of instances that I need for this class will not be known before execution, but I want each option to myArglead to a different instance of singleton (so that requesting the same value returns the same instance twice, but different arguments return different instances).

Does anyone know of a good, preferably built-in way to do this?

I found an article written for an older version of Ninject How to provide one instance for each activation option , but was hoping there would be a finer solution for the newer version.

Edit

Here is what I went, adapted from Akim below:

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();
}
+5
1

, IBindingNamedWithOrOnSyntax<T> InScope(Func<IContext, object> scope) MyClass

, , , , , (.. ).

, Func<IContext, object> scope , .

:

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;
                });
    }
}

ps: unittests

+3

All Articles