将ICollection <t>分配给ICollection属性

时间:2016-01-08 14:41:41

标签: c#

是的,我知道ICollectionICollection<T>是两回事。让我来描述我尝试的内容......

这就是我想做的事情:

public class SubmissionListViewModel
{
    public ICollection<ProjectSubmissionViewModel> Submissions { get; set; }

    public ReportBase GetContribAuthorsReport()
    {
        var report = new ContribAuthorsReport{ ReportType = "CSV" };

        var chapAffil = new ChapterAffiliates {ReportItems = Submissions};

        report.ReportSections.Add(chapAffil);
        // AT this point, I would expect report.ReportSections.First().ReportItems 
        // to have the records from Submissions, but I have `null`.

        return report;
    }
}

问题: 为什么report.ReportSections.First().ReportItems为空? (见上面代码中的评论。)

以下是ContribAuthorsReportChapterAffiliates的定义方式:

public class ContribAuthorsReport : ReportBase
{
    public ContribAuthorsReport()
    {
        ReportSections = new List<ReportSectionBase>();
    }

    public override string ReportName { get { return "Contributing Affiliates' Contact Information"; } }
}

public class ChapterAffiliates : ReportSectionBase
{
    public override string ReportSectionName { get { return "Chapter Affiliates"; } }

    // This is what I have now
    new public ICollection<ProjectSubmissionViewModel> ReportItems { get; set; }

    // This won't compile
    //public override ICollection<ProjectSubmissionViewModel> ReportItems { get; set; }

    // This would compile, but breaks GetContribAuthorsReport()
    //public override ICollection ReportItems { get; set; }

}

我将有其他继承自ReportSectionBase的类,它们将具有不同的ICollection模型。我认为这个问题源于我如何定义基类。 (见下文)

我的基础课程。

public abstract class ReportBase
{
    virtual public string ReportType { get; set; }

    virtual public string ReportName { get; set; }

    public ICollection<ReportSectionBase> ReportSections { get; set; }

}

public abstract class ReportSectionBase 
{
    virtual public string ReportSectionName { get; set; }

    virtual public ICollection ReportItems { get; set; }
} 

更新:最终结果 - 这就是我现在正在使用的内容。

public class ReportBase
{
    public ReportBase()
    {
        ReportSections = new List<IReportSection>();
    }

    public string ReportType { get; set; }

    public string ReportName { get; set; }

    public ICollection<IReportSection> ReportSections { get; set; }

}
public interface IReportSection
{
    string ReportSectionName { get; }

    ICollection ReportItems { get; set; }
}

public class ReportSection<T> : IReportSection
{
    public string ReportSectionName { get; set; }

    public ICollection<T> ReportItems { get; set; }

    ICollection IReportSection.ReportItems
    {
        get { return ReportItems as ICollection; }
        set { ReportItems = value as ICollection<T>; }
    }
}

这使我可以像这样简单地定义报告:

public ReportBase GetContribAuthorsReport
(
    ICollection<ProjectAffiliateViewModel> projectAffiliates, 
    ICollection<SubmissionAffiliateViewModel> submissionAffiliates
)
{
    var caReport = new ReportBase { ReportType = "CSV", ReportName = "Reviewers' Contact Information" };

    caReport.ReportSections.Add(new ReportSection<ProjectAffiliateViewModel> { ReportItems = projectAffiliates });
    caReport.ReportSections.Add(new ReportSection<SubmissionAffiliateViewModel> { ReportItems = submissionAffiliates });

    return caReport;
}

2 个答案:

答案 0 :(得分:1)

问题是您的ChapterAffiliates类隐藏了从ReportSectionBase继承的ReportItems属性。请参阅MSDN documentation on the new modifier。通过集合访问实例时,引用的类型为ReportSectionBase。因此,尚未设置ReportItems属性。访问ChapterAffiliates实例的ReportItems属性的唯一方法是在类型为ChapterAffiliates的引用上访问它。

ChapterAffiliates a = new ChapterAffiliates { ReportItems = Submissions};
ReportSectionBase b = new ChapterAffiliates { ReportItems = Submissions};

// a.ReportItems == Submissions; returns true
// b.ReportItems == null; returns true
// ((ChapterAffiliates) b).ReportItems == Submissions; returns true 

要解决这个问题,我会将ReportSectionBase作为通用类。 type参数将指定ReportItems的类型。这样,您不需要将集合设置为虚拟,因为它将在基类中提供。此外,它保证一切类型安全。在我看来,这是一件好事。

public abstract class ReportBase<TReportSection, TReportItem> where TReportSection : ReportSectionBase<TReportItem>
{
    public virtual string ReportType { get; set; }
    public virtual string ReportName { get; set; }
    public ICollection<TReportSection> ReportSections { get; set; }
}

public abstract class ReportSectionBase<TReportItem>
{
    public virtual string ReportSectionName { get; set; } 
    public ICollection<TReportItem> ReportItems { get; set; }
}

public class ChapterAffiliates : ReportSectionBase<ProjectSubmissionViewModel>
{
    public override string ReportSectionName { get { return "Chapter Affiliates"; } }             
}

public class ContribAuthorsReport : ReportBase<ChapterAffiliates, ProjectSubmissionViewModel>
{
    public ContribAuthorsReport()
    {
        ReportSections = new List<ChapterAffiliates>();
    }

    public override string ReportName { get { return "Contributing Affiliates' Contact Information"; } }
}

另外,请考虑不公开可设置的集合属性。不建议在MSDN collection guidelines

答案 1 :(得分:1)

由于您使用new隐藏了该集合,因此该方法不是虚拟的,这意味着当您使用ReportSectionBase变量时,它将不会使用您的新集合。

解决此问题的最简单方法是将抽象类更改为接口,这允许您显式实现基类,但也公开您的泛型集合。

public abstract class ReportBase
{
    virtual public string ReportType { get; set; }

    virtual public string ReportName { get; set; }

    public ICollection<IReportSection> ReportSections { get; set; }

}

public interface IReportSection
{
    string ReportSectionName { get; }

    ICollection ReportItems { get; set; }
}

public class ContribAuthorsReport : ReportBase
{
    public ContribAuthorsReport()
    {
        ReportSections = new List<IReportSection>();
    }

    public override string ReportName { get { return "Contributing Affiliates' Contact Information"; } }
}

public class ChapterAffiliates : IReportSection
{
    public string ReportSectionName { get { return "Chapter Affiliates"; } }

    public ICollection<ProjectSubmissionViewModel> ReportItems { get; set; }

    ICollection IReportSection.ReportItems {
        get { return ReportItems as ICollection; }
        set { ReportItems = value as ICollection<ProjectSubmissionViewModel>; }
    }

}