StructureMap:将运行时参数传递给选定的构造函数

时间:2014-11-28 17:37:15

标签: c# .net inversion-of-control structuremap structuremap3

我想选择一个构造函数并传入运行时参数。我知道如何选择带有注册表提供的参数的构造函数,我也知道如何提供运行时参数。但我看不出将两者结合在一起的方法。

班级:

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解决方案。看起来它们几乎可以工作的一些选项是使用2.x中没有出现的2.x语法 - 或者它移动了)

1 个答案:

答案 0 :(得分:0)

我找到了几个解决方案。

  1. [预设构造函数]
  2. 将属性标记为您想要的构造函数,然后关闭。绝对不是我的第一选择,因为它将注册拆分为实现,以及使用IoC属性的其他问题。但这是最简单的,如果您的代码中的IoC容器属性没有问题,请使用它。

    1. Policies.ConstructorSelector()
    2. 下面是一种使用构造函数选择器策略来查找构造函数的方法,并且使用多个选择器按类型分隔。请注意,这可以作为扩展方法解决方案,但我不想让它复杂化而不是需要。

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