Единство по требованию разрешения свойств Interfce


У меня есть интерфейс 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 3

1 ответ:

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

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

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

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

Вот пример:

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

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

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