Подтвердить что ты не робот

Как использовать StructureMap с открытыми незакрытыми типами, используя Scan с "жадным" конструктором

Между различными вопросами и сообщениями в блоге имеется довольно разумная документация по теме открытых дженериков и StructureMap. К сожалению, я должен упустить что-то, поскольку мои попытки использовать scan для выполнения конфигурации вместе с реализацией класса, у которой есть "жадный" конструктор, еще не работают.

Я хочу, чтобы StructureMap захватил экземпляр класса ниже через ссылки на его реализованный интерфейс. ToCsvService существует в unreferenced сборке под названием Infrastructure. IToCsvService существует в ссылочной сборке под названием Core. Как вы видете ToCsvService имеет "жадный" конструктор.

public class ToCsvService<TSource> : IToCsvService<TSource>
{
    public ToCsvService(ICollection<TSource> collection)
    {
    }
}

Я могу сообщить StructureMap о ToCsvService с помощью метода ConnectImplementationsToTypesClosing.

ObjectFactory.Initialize(cfg =>
{
    cfg.Scan(scan =>
    {
        scan.Assembly("Infrastructure");
        scan.WithDefaultConventions();

        // even with this call StructureMap cannot use ToCsvService
        // instance of IToCsvService (though wouldn't expect it to)
        scan.ConnectImplementationsToTypesClosing
            (typeof(IToCsvService<>));
    });
});

Из метода ObjectFactory.WhatDoIHave() кажется, что StructureMap знает ToCsvService.

PluginType                            Name                                                                                                            Description                                                                                                                          
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IToCsvService`1 (IToCsvService`1)                                                                                                                                                                                                                                      
Scoped as:  Transient                                                                                                                                                                                                                                                                                  
                                      6202a7ee-89a4-4edd-831d-4867b7dd1a7e                                                                            Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 
                                      Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null   Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                   

Однако, когда я указываю IToCsvService<CustomerViewModel> в конструкторе контроллера, он генерирует исключение

Код исключения StructureMap: 202 Нет экземпляра по умолчанию, определенного для PluginFamily Core.Services.IToCsvService`1 [[UI.Models.MachineForm, UI, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null]], Core, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null

Я предполагаю, что это потому, что StructureMap не имеет понятия, что передать "жадному" конструктору ToCsvService. Есть ли что-то, что я могу сделать StructureMap способным хорошо играть с этим конструктором? Нужно ли мне переключаться с конструктора и просто устанавливать свойство коллекции после создания экземпляра?

Вопрос Structuremap и общие типы детализирует несколько, я пытаюсь сделать, но не использует сканирование для этого. В ответе , предоставленном Джошуа Фланаганом, используется конфигурация For(x).Use(y), которая может работать, если я не сканирую сборка, потому что у меня нет ссылки ToCsvService.

Изменить

Я хотел посмотреть, будет ли использование другого механизма, позволяющего StructureMap идентифицировать экземпляры ToCsvService<>. Он изменяет то, что сообщается в ObjectFactory.WhatDoIHave(), и выдает другое исключение. Вот пример использования AddAllTypesOf.

ObjectFactory.Initialize(cfg =>
{
    cfg.Scan(scan =>
    {
        scan.Assembly("Infrastructure");
        scan.WithDefaultConventions();

        scan.AddAllTypesOf(typeof(IToCsvService<>));
    });
});

После использования выше дамп из ObjectFactory.WhatDoIHave() равен

PluginType                           Name                                                                                                                                 Description                                                                                                                                            
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IToCsvService`1 (IToCsvService`1)    Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                        Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                   
Scoped as:  Transient

                                     Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                        Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                   
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
IToCsvService`1 (IToCsvService`1)    Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                        Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                   
Scoped as:  Transient

                                     Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null                        Configured Instance of Infrastructure.Services.ToCsvService`1, Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null

В этой конфигурации я бросаю это исключение:

Код исключения StructureMap: 202 Нет экземпляра по умолчанию для PluginFamily System.Collections.Generic.ICollection`1 [[UI.Models.MachineForm, UI, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = null]], mscorlib, Version = 4.0.0.0, Culture = нейтральный, PublicKeyToken = b77a5c561934e089

Для меня исключение указывает, что StructureMap знает, что ему требуется ICollection<MachineForm> для создания экземпляра ToCsvService, но не знает, откуда его получить. Которая идет в комментарий Джимми от ниже об использовании StructureMap и Встраивание конструктора set. Однако это не представляется возможным без добавления явной ссылки на сборку инфраструктуры.

Несколько связанных вопросов в StructureMap и Generics

Сообщения в блогах, касающиеся StructureMap и Generics

4b9b3361

Ответ 1

Существуют ли какие-либо конкретные реализации IToCsvService? Или просто открытый тип ToCsvService?

ConnectImplementationsToTypesClosing предназначен для подключения чего-то вроде конкретного CustomerViewModelToCsvService к IToCsvService < > . Если вы хотите подключить открытые классы для открытия интерфейсов, вам понадобится:

For(typeof(IToCsvService<>)).Use(typeof(ToCsvService<>));

Здесь я подключаю открытый тип интерфейса к классу открытого класса.

Ответ 2

На самом деле в текущей версии это должно быть очень просто. Все, что вам нужно сделать, это предоставить аргумент, когда вы вызываете, чтобы получить новый экземпляр объекта. Для этого вы используете метод "С" на объекте.

Это позволяет использовать жадный конструктор. Однако это также означает, что вы должны знать, что вам нужна коллекция в этом примере. Таким образом, это не оптимальный метод инъекционного состояния.

var newObject = ObjectFactory.With<ICollection<CustomerViewModel>>(SomeCollection)
                .GetInstance<IToCsvService<CustomerViewModel>>();