5

Ninject を使用して、渡されたコンストラクター引数でいくつかのオブジェクトをインスタンス化しています。

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

このクラスに必要なインスタンスの数は実行時までわかりませんが、私がやりたいことは、各バリエーションのmyArg結果が異なるシングルトン インスタンスになるようにすることです (同じ値を 2 回要求すると、同じインスタンスが返されますが、異なるインスタンスが返されます)。 args は異なるインスタンスを返します)。

これを行うための優れた、できれば組み込みの方法を知っている人はいますか?

古いバージョンの Ninjectのアクティベーション パラメーターのバリエーションごとに 1 つのインスタンスを確保する方法について書かれた記事を見つけましたが、新しいバージョンにはより適切なソリューションがあることを期待していました。

編集

以下の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();
}
4

1 に答える 1

3

バインディング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:単体テストを含む完全なサンプル コード

于 2013-01-24T14:54:43.547 に答える