0

コンストラクターを選択し、ランタイム引数を渡したいです。レジストリが提供する引数を使用してコンストラクターを選択する方法を知っており、ランタイム引数を提供する方法も知っています。しかし、両方を組み合わせる方法がわかりません。

クラス:

public class SomeClass
{
    // This is the one I want to be the default by selecting it.
    public SomeClass(string arg1, AnArgClass arg2) { }

    // This is default if I don't purposely select it.
    public SomeClass(string arg1, string arg2, string arg3) { }
}

登録方法(これが機能しないことはわかっています):

ForConcreteType<SomeClass>()
    .Configure.SelectConstructor(() => new SomeClass(arg1?, arg2?));  I don’t see a way to get the runtime args in…

これは、登録することができれば、それを作成して引数を提供する方法です。

var obj1 = _container.With(“arg1”).EqualTo(aRunTimeArg1)
    .With<AnArgClass>(aRunTimeArg2)
    .GetInstance<SomeClass>();

前もって感謝します。

(注:StructureMap 3.xソリューションを探しています。ほとんど機能しているように見えるオプションのいくつかは、3.xでは利用できないように見える2.x構文を使用しています-または移動しました)

4

1 に答える 1

0

私はいくつかの解決策を見つけました。

  1. [デフォルトコンストラクタ]

属性に必要なコンストラクターをタグ付けしてください。ICで属性を使用する他の問題の中でも、登録を実装に分割するため、間違いなく私の最初の選択ではありません。しかし、それが最も簡単で、コード内の IoC コンテナー属性に問題がない場合は、試してみてください。

  1. ポリシー.コンストラクターセレクター()

以下は、コンストラクター セレクター ポリシーを使用してコンストラクターを検索し、複数のセレクターをタイプで区切る方法です。これは拡張メソッドのソリューションにすることができますが、必要以上に複雑にしたくないことに注意してください。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using StructureMap;
using StructureMap.Configuration.DSL;
using StructureMap.Pipeline;
using StructureMap.TypeRules;

public class SomeClass
{
    // This is the one I want to be the default by selecting it.
    public SomeClass(string arg1, AnArgClass arg2) { }

    // This is default if I don't purposely select it.
    public SomeClass(string arg1, string arg2, string arg3) { }
}

public class AnArgClass { }

public class SampleRegistry : Registry
{
    public SampleRegistry()
    {
        var selectors = new SelectorsList();
        Policies.ConstructorSelector(selectors);

        For<SomeClass>().Use<SomeClass>();
        selectors.Add<SomeClass>(new SelectorByTypes(new[] { typeof(string), typeof(AnArgClass) }));
    }
}

public class SelectorByTypes : IConstructorSelector
{
    private Type[] mArgumentsTypes;

    public SelectorByTypes(IEnumerable<Type> argumentsTypes)
    {
        mArgumentsTypes = argumentsTypes.ToArray();
    }

    public ConstructorInfo Find(Type pluggedType)
    {
        return pluggedType.GetConstructor(mArgumentsTypes); // GetConstructor() ext in SM.TypeRules
    }
}

public class SelectorsList : IConstructorSelector
{
    // Holds the selectors by type
    private Dictionary<Type, IConstructorSelector> mTypeSelectors = new Dictionary<Type, IConstructorSelector>();
    // The usual default, from SM.Pipeline
    private GreediestConstructorSelector mDefaultSelector = new GreediestConstructorSelector(); 

    public void Add<T>(IConstructorSelector selector)
    {
        mTypeSelectors.Add(typeof(T), selector);
    }

    public ConstructorInfo Find(Type pluggedType)
    {
        ConstructorInfo selected = null;
        if (mTypeSelectors.ContainsKey(pluggedType))
        {
            var selector = mTypeSelectors[pluggedType];
            selected = selector.Find(pluggedType);
        }
        else
        {
            selected = mDefaultSelector.Find(pluggedType);
        }
        return selected;
    }
}

拡張子としては、次のようになります。

 For<SomeClass>()
      .Use<SomeClass>()
      .SetConstructor(selectors, new Type[] { typeof(string), typeof(AnArgClass) });


public static class Extensions
{
    public static SmartInstance<TConcreteType, TPluginType> SetConstructor<TConcreteType, TPluginType>(
        this SmartInstance<TConcreteType, TPluginType> instance,
        ConstructorSelectors constructors,
        IEnumerable<Type> types)
        where TConcreteType : TPluginType
    {
        constructors.Add(typeof(TPluginType), new ArgTypesConstructorSelector(types));
        return instance;
    }
}
于 2014-11-28T23:15:05.540 に答える