c# - 在单例范围内注入(inject) Memoize 实例

标签 c# dependency-injection inversion-of-control ninject

我正在使用 Ninject 来实例化一些传递了构造函数 arg 的对象,例如:

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

我需要的此类实例的数量直到运行时才知道,但我想做的是确保 myArg 的每个变体都会产生不同的单例实例(因此要求相同的值两次返回相同的实例,但不同的参数返回不同的实例)。

有谁知道这样做的好方法,最好是内置的方法?

我找到一篇为旧版 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> InScope(Func<IContext, object> scope) 提供自定义范围来实现要求行为MyClass 的方法绑定(bind)

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 返回第一个构造函数参数的值并确保 不会收集它。

这是一个片段:

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

附注:full sample code with unittests

关于c# - 在单例范围内注入(inject) Memoize 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14502396/

相关文章:

c# - 流行的 "volatile polled flag"模式坏了吗?

c# - 在 C# 中显示小数到第 n 位

c# - 在 C# 中解析大型 XML(大小为 1GB)的最佳方法是什么?

c# - 如何随机分配按钮内容和颜色?

c# - .Net Web Api 2.2 端点中的依赖注入(inject)不可用

unit-testing - MassTransit 服务总线配置和单元测试

c# - 我应该如何管理类依赖/重构?

mvvm - Caliburn.Micro + Unity 2.1 + MVVM : example code

c# - IoC 容器是否取代了工厂的使用

c# - Ninject 工厂扩展和 InCallScope 没有给出预期的结果