Единство по требованию разрешения свойств 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 ответ:
То, что вы делаете, называется расположением службы, а считается анти-паттерном.
Я собираюсь предложить другой способ получить вашу зависимость. Пожалуйста, обратите внимание, что я собираюсь предоставить некоторый общий код просто в качестве примера. И также я собираюсь говорить только о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
.