Interfce属性的Unity按需解析

时间:2015-10-17 06:30:01

标签: c# dependency-injection unity-container dependency-resolver

我有一个接口IRDFReport和一个实现它的基类BaseReportViewReport属性是重型对象,只有在实际请求报告时才应解析。我使用了两个简单的字符串后缀来查找对象的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);

1 个答案:

答案 0 :(得分:3)

您正在做的事情称为服务地点和is considered an anti-pattern

我将建议一种获得依赖关系的不同方法。请注意,我将提供一些通用代码作为示例。而且我也只会谈论IReport。可以类似地对待其他依赖。

我建议使用构造函数注入。您的BaseReport依赖于IReport,但它希望能够仅在以后按需获取(并构建它)。

执行此操作的一种方法是使用abstract factory

以下是一些例子:

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

然后,您可以创建此工厂的实现并将其注入BaseReport的构造函数。这将使BaseReport能够根据需求请求IReport依赖。

另一种解决方案是使用.NET Lazy类。此类允许您在第一次尝试使用它时创建依赖项。 Unity对Lazy类提供本机支持(请参阅this reference)。

以下是如何使用它的示例:

您可以将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对象。