统一按需解析接口属性
本文关键字:接口 属性 | 更新日期: 2023-09-27 18:18:02
我有一个接口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);
您所做的被称为服务定位,并且被认为是一个反模式。
我将建议一个不同的方法来获得你的依赖。请注意,我将提供一些泛型代码作为示例。我也只讲IReport
。其他依赖项也可以类似地处理。
我的建议是使用构造函数注入。您的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; }
}
}
在Composition根目录(你使用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
对象。