Инъекция сеттера StructureMap в открытый универсальный тип? - PullRequest
1 голос
/ 14 января 2010

Используя StructureMap, я пытаюсь использовать сеттерное внедрение для открытого универсального типа.

У меня есть абстрактный обобщенный класс:

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

Я хочу использовать Setter Injection для разрешения «Bar» на любых наследниках Foo. Я знаю, что могу сделать это с помощью атрибута [SetterDependency] в Bar, но я хочу избежать декорирования своего класса таким образом.

Я думал, что мог бы использовать ForConcreteType в DSL следующим образом:

ForConcreteType (TypeOf (Foo <,>)) Configure.Setter () IsTheDefault ();..

Но ForConcreteType имеет только общую реализацию.

Я попытался сделать это в конфигурации следующим образом:

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

Это компилирует, но выдает исключение времени выполнения "нельзя подключить к типу" при попытке разрешить.

Кто-нибудь знает, как в этом случае выполнить инъекцию сеттера? Спасибо!

EDIT:

В соответствии с просьбой, вот подробный пример того, чего я пытаюсь достичь:

[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 Ответ

1 голос
/ 14 января 2010

Я предполагаю, что вы получаете Foo по IMyInterface, а не по запросу Foo. Так что вы хотите сделать для (typeof (IMyInterface <,>)). Этот код работает для меня (используя исходный код транка):

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 => set.Matching (...))

...