3

我有一个接口IRDFReport和一个实现它的基类BaseReport。和属性是重对象ViewReport只有在实际请求报告时才应该解析。我使用了两个简单的字符串后缀来查找对象的命名映射ViewReport属性。

我想使用 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);
4

1 回答 1

3

您正在做的事情称为 Service Location 并且被认为是一种反模式

我将建议一种不同的方式来获得你的依赖。请注意,我将提供一些通用代码作为示例。我也将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 Root(使用 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对象。

于 2015-10-17T21:24:18.107 回答