开发者

StructureMap setter injection in open generic type?

Using StructureMap, I'm trying to use setter injection on an open generic type.

I have an abstract generic class:

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

I want to use Setter Injection to resolve "Bar" on any inheritors of Foo. I know I can do this using the [SetterDependency] attribute on Bar but I want to avoid decorating my class that way.

I'd thought I could use ForConcreteType in the DSL like so:

ForConcreteType(typeof(Foo<,>)).Configure.Setter().Is开发者_高级运维TheDefault();

But ForConcreteType only has a generic implementation.

I have tried to do this in configuration as follows:

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

This compiles but throws a "cannot be plugged into type" runtime exception when it tries to resolve.

Does anyone know how to accomplish setter injection in this case? Thanks!

EDIT:

As requested, here is an elaborated example of what I'm trying to achieve:

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


I assume you are retrieving Foo by IMyInterface - not by asking for a Foo. So you will want to do For(typeof(IMyInterface<,>)). This code works for me (using the trunk source code):

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

Alternatively, you could set up a convention, so that ANY type retrieved from the container that has a property of type ISomeDependency will get populated:

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

You can also base your conventions on other criteria using x.SetAllProperties(set => set.Matching(...))

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜