StructureMap setter注入开放泛型类型?

时间:2010-01-13 22:05:40

标签: generics dependency-injection structuremap

使用StructureMap,我正在尝试在开放泛型类型上使用setter注入。

我有一个抽象的泛型类:

public abstract class Foo<T1, T2> : IMyInterface<T1,T2>
{
   public ISomeDependency Bar { get; set; }
}

我想使用Setter Injection来解析Foo的任何继承者的“Bar”。我知道我可以使用Bar上的[SetterDependency]属性来执行此操作,但我想避免以这种方式装饰我的类。

我以为我可以在DSL中使用ForConcreteType:

ForConcreteType(typeof运算(美孚&LT;,&GT))Configure.Setter()IsTheDefault();

但ForConcreteType只有一个通用的实现。

我尝试在配置中执行此操作,如下所示:

For(typeof (Foo<,>))
.Use(typeof (Foo<,>)).SetterDependency<ISomeDependency>("Bar").IsAutoFilled();

这会编译,但在尝试解析时会抛出“无法插入类型”运行时异常。

在这种情况下,有谁知道如何完成二传手注射?谢谢!

编辑:

根据要求,这是我正在努力实现的一个详细示例:

[Test]
public void can_resolve_open_generic_type_using_setter_injection()
{
   ObjectFactory.Initialize(x =>
                                {
x.For<ISession>().Use<DatabaseSession>();
// uncomment next line and it resolves:
// x.SetAllProperties(set => set.OfType<ISession>());
x.ForRequestedType<IHandler<OrderReceivedMessage>>()
.TheDefaultIsConcreteType<OrderHandler>();

                                });

   var instance = ObjectFactory.Container.GetInstance<IHandler<OrderReceivedMessage>>();

   instance.ShouldBeOfType<DatabaseTransactionHandler<OrderReceivedMessage>>();
   instance.ShouldBeOfType<OrderHandler>();

   var asTransactionHandler = (DatabaseTransactionHandler)instance;
   Assert.IsNotNull(asTransactionHandler.Session);

}

public interface IHandler<TMessage>
{
    void Handle(TMessage message);
}

public abstract class DatabaseTransactionHandler<TMessage> : IHandler<TMessage>
{

    // need to inject this with the default ISession
    // works when using [SetterDependency] attribute
    public ISession Session { get; set; }

    public abstract void DoHandle(TMessage message);

    public virtual void Handle(TMessage message)
    {
          using (ITransaction transaction = Session.CreateTransaction())
          {
                try
                {
                    DoHandle(message);
                    transaction.Commit();
                }
                catch (Exception handlerException)
                {
                    transaction.Rollback();
                    throw;
                }                   
          }
     }
}


public class OrderHandler : DatabaseTransactionHandler<OrderReceivedMessage>
{
    public override void DoHandle(OrderReceivedMessage message)
    {
       Order order = CreateOrderFromMessage(message);
       Session.Save(order);
    }
}

1 个答案:

答案 0 :(得分:1)

我假设您正在通过IMyInterface检索Foo - 而不是通过要求Foo。所以你想做For(typeof(IMyInterface&lt;,&gt;))。 此代码适用于我(使用主干源代码):

var container = new Container(x =>
{
    x.For<ISomeDependency>().Use<TheDependency>();
    x.For(typeof (IMyInterface<,>)).Use(typeof (Foo<,>)).SetterDependency<ISomeDependency>("Bar").IsAutoFilled();
});

var instance = (Foo<string, bool>)container.GetInstance(typeof (IMyInterface<string, bool>));
Console.WriteLine(instance.Bar.GetType().Name);

或者,您可以设置约定,以便从具有ISomeDependency类型属性的容器中检索的任何类型将被填充:

var container = new Container(x =>
{
    x.For<ISomeDependency>().Use<TheDependency>();
    x.For(typeof (IMyInterface<,>)).Use(typeof (Foo<,>));
    x.SetAllProperties(set => set.OfType<ISomeDependency>());
});

您还可以使用x.SetAllProperties(set =&gt; set.Matching(...))

将您的约定基于其他条件