Unity On-Demand Resolve Interfce Properties

У меня есть интерфейс IRDFReport и базовый класс BaseReport который реализует это. View а также Report свойства являются тяжелыми объектами и должны разрешаться только тогда, когда отчет действительно запрашивается. Я использовал два простых суффикса строки для поиска именованных отображений View а также Report свойства объектов.

Я хотел бы использовать Unity для разрешения тяжелых объектов по требованию, а также разрешать все отчеты, чтобы иметь их список. Является ли этот вид разрешения в get методы, что я могу сделать для этого?

public interface IRDFReport
{
    UserControl View { get; }
    string ReportName { get; }
    string Name { get; set; }
    Task<bool> GenerateReport(SynchronizationContext context);
    DevExpress.XtraReports.IReport Report { get; set; }
}

BaseReport который реализует этот интерфейс:

public class BaseReport : IRDFReport
{

    public DevX.IReport Report
    {
        get
        {
            return ReportManager.myContainer.Resolve<IReport>(ReportName + ReportManager.Report_Suffix) as XtraReport;
        }
    }

    public UserControl View
    {
        get
        {
            return ReportManager.myContainer.Resolve<UserControl>(ReportName + ReportManager.View_Suffix);
        }
    }

    ///
    /// other members
    ///
}       

И в моем диспетчере отчетов я регистрирую их так:

public const string View_Suffix = ".View";
public const string Report_Suffix = ".XtraReport";

Reports = new List<IRDFReport>();

myContainer.RegisterType<IReport, BalanceSheetXtraReport>(nameof(BalanceSheetReport) + Report_Suffix, new ContainerControlledLifetimeManager());
myContainer.RegisterType<UserControl, BalanceSheetView>(nameof(BalanceSheetReport) + View_Suffix, new ContainerControlledLifetimeManager());

  ///
  /// registering other reports inherited from BaseReport
  ///

myContainer.RegisterTypes(
    AllClasses.FromLoadedAssemblies()
    .Where(type => typeof(IRDFReport).IsAssignableFrom(type)),
    WithMappings.FromAllInterfaces,
    WithName.TypeName);

var reports = myContainer.ResolveAll<IRDFReport>().Where(x => !string.IsNullOrEmpty(x.Name)).ToList();
Reports.AddRange(reports);

1 ответ

Решение

То, что вы делаете, называется Service Location и считается анти-паттерном.

Я собираюсь предложить другой способ получить вашу зависимость. Обратите внимание, что в качестве примера я приведу общий код. А также я буду говорить о IReport только. Другая зависимость может рассматриваться аналогично.

Я предлагаю использовать Constructor Injection. Ваш BaseReport имеет зависимость от IReport, но он хочет иметь возможность получить его (и построить его) только позднее по требованию.

Один из способов сделать это - использовать абстрактную фабрику.

Вот несколько примеров:

public interface IReportFactory
{
    IReport Create(); //this can also take parameters
}

Затем вы можете создать реализацию этой фабрики и внедрить ее в конструктор BaseReport, Это позволит BaseReport просить IReport зависимость от спроса.

Другое решение - использовать класс.NET Lazy. Этот класс позволяет вам создать зависимость при первой попытке его использования. Unity имеет встроенную поддержку Lazy класс (см. эту ссылку).

Вот пример того, как вы бы это использовали:

Вы можете ввести Lazy<IReport> в ваш BaseReport класс как это:

public class BaseReport
{
    private readonly Lazy<IReport> m_LazyReport;

    public BaseReport(Lazy<IReport> lazy_report)
    {
        m_LazyReport = lazy_report;
    }

    public IReport Report
    {
        get { return m_LazyReport.Value; }
    }
}

В корне композиции (место, где вы используете контейнер DI), выполните следующие действия:

UnityContainer container = new UnityContainer();

container.RegisterType<IReport, Report>("name");

container.RegisterType<BaseReport>(
    new InjectionConstructor(
        new ResolvedParameter<Lazy<IReport>>("name")));

Достаточно просто зарегистрироваться IReportи тогда Unity сможет решить Lazy<IReport> без каких-либо проблем, и он знает, чтобы заставить его работать таким образом, что только когда Lazy Доступ к значению объекта, что он идет вперед и создает Report объект.

Другие вопросы по тегам