【问题标题】:Generic override method in in Polymorphic object多态对象中的通用覆盖方法
【发布时间】:2012-11-27 19:28:19
【问题描述】:

我在多态基类中使用泛型覆盖方法的语法有问题。

这是用于报告引擎的基本架构;我在一个基类中有两个虚拟方法和大量从基类派生的对象,它们覆盖了这些方法。

在客户端代码中,调用了一个报表工厂对象,该对象根据传入的字符串以及用作参数的对象数组实例化其中一个对象。方法的字符串名称来自数据库并位于多选列表中,因此用户可以选择任意数量的报告来运行。

现在的要求是创建 PDF 文档,这很容易做到,因为通用方法只有一个已知类型。我想做的是扩展它的用处并返回任何类型的列表。

这是我的虚拟方法的签名。第一个是强类型的,我可以完美地工作,第二个,我有问题。他们在这里:

    /// <summary>
    /// Virtual method to run report from a Word mail merge template
    /// </summary>
    /// <param name="Template">Word mail merge template name</param>
    /// <returns>PDF Document</returns>
    public virtual PdfDocument RunReportPDFOutFromWordTemplate( string TemplateName )
    {
        try
        {
            return new PdfDocument();
        }
        catch( Exception )
        {
            throw;
        }
    }

    /// <summary>
    /// Virtual method to run report outputting a generic list
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public virtual List<T> RunReportListOut<T>()
    {
        try
        {
            return new List<T>();
        }
        catch( Exception )
        {
            throw;
        }
    }

然后在我的代码中,我通过调用我的 ReportFactory 类来调用该对象。先是 ReportFactory 类,然后是调用代码:

    public static class ReportFactory
{
    /// <summary>
    /// Get an object from the Report Factory
    /// </summary>
    /// <param name="ObjectName">Name of the Object</param>
    /// <param name="ParamList">List of parameters the object constructor is expecting</param>
    /// <returns></returns>
    public static ReportBase GetObject( string ObjectName, object[] ParamList )
    {
        try
        {
            return (ReportBase)Activator.CreateInstance( Type.GetType( Utils.GetCurrentNamespaceName() + "." + ObjectName ), ParamList );
        }
        catch( Exception )
        {
            throw;
        }
    }
}

现在是调用代码:

                        ParamList = new object[] { r.Name, r.MethodPointer, this.dpStartDate.SelectedDate, this.dpEndDate.SelectedDate, this.AppData.ActivePatient };
                    rb = ReportFactory.GetObject( r.MethodPointer, ParamList );

                    PdfDocument pdfDoc = rb.RunReportPDFOutFromWordTemplate( ConfigurationManager.AppSettings[ "ReportTemplateLocation" ].ToString() + r.MethodPointer + ConfigurationManager.AppSettings[ "ReportTemplateType" ].ToString() );

有效方法的代码在这里并不真正相关,我不想通过发布它来浪费任何人的时间。它适用于我需要它做的事情。

问题是我希望能够使用相同的报告工厂返回一个列表。当我覆盖我的方法时,我收到以下错误:Cannot implicitly convert type 'System.Collections.Generic.List&lt;FMCNA_Model.Cycle&gt;' to 'System.Collections.Generic.List&lt;Cycle&gt;

这里是被覆盖的代码和一个辅助方法:

    public override List<Cycle> RunReportListOut<Cycle>()
    {
        try
        {
            List<Cycle> CycleList = this.GetCycleList();
            return CycleList;
        }
        catch( Exception )
        {
            throw;
        }
    }

    private List<Cycle> GetCycleList()
    {
        try
        {
            return Cycle.PatientForDateRange( this.CurrentPatient.PatientIDInternal, this.StartDate, this.EndDate );
        }
        catch( Exception )
        {
            throw;
        }
    }

我很难过如何做到这一点。抱歉这个问题太长了,我认为最好把所有内容都集中在覆盖语法上。

谢谢,

迈克

【问题讨论】:

  • 为什么你的代码中到处都是无意义的 try/catch 块?摆脱所有这些 - 您的代码将更清晰,更易于阅读。同样,为什么要打扰您的辅助方法?只需将所有这些移至RunReportListOut,因为它不会做任何其他事情......

标签: c# generics polymorphism overriding


【解决方案1】:
public override List<Cycle> RunReportListOut<Cycle>()

这将创建一个常规泛型方法,其类型参数恰好命名为Cycle
public override List&lt;T&gt; RunReportListOut&lt;T&gt;()没什么区别;类型参数仍然可以是任何类型。

你想做的事是完全不可能的;你不能用非泛型方法覆盖泛型方法。

【讨论】:

  • 如果我正确理解了您的答案,您是说这应该可行,但我无法让它发挥作用。有什么想法吗?
  • @MikeMalter:不。它不能工作。 en.wikipedia.org/wiki/Liskov_substitution_principle
  • @MikeMalter:请参阅我的回答 alongside 以获取有关您可能希望如何进行的建议。
【解决方案2】:

正如 SLaks 所说,您在尝试使用名为 T类型参数 声明泛型虚拟方法时遇到了问题 - 但随后您尝试使用另一种泛型方法覆盖它使用Cycle 作为类型参数。这真的不是你的意思。泛型方法意味着 调用者 可以指定类型参数 - 而您可能想要返回 List&lt;Cycle&gt;

我强烈怀疑你应该有一个通用的type,并带有一个使用该类型参数的方法声明。例如:

public abstract class Report<T>
{
    public abstract List<T> RunReportListOut();
}

然后

public class CycleReport : Report<Cycle>
{
    public override List<T> RunReportListOut()
    {
        ...
    }
}

如果您想要拥有两种类型,则以不同的方式命名它们会更简洁...然后您需要在方法中添加转换。或者,只需将这两种类型合并为一种,这样可能会更简洁。

此外,正如我在评论中指出的那样,您应该删除您的 try/catch 块。它们都没有任何好处,而且它们会弄乱你的代码——目前在你的方法的主体中,你总共有 6 行“主体”代码和 35 行毫无意义的 try/catch。一旦你删除了这些,很明显你的GetCycleList 辅助方法也毫无意义。你可以写:

public override List<Cycle> RunReportListOut()
{
    return Cycle.PatientForDateRange(this.CurrentPatient.PatientIDInternal,
                                     this.StartDate, this.EndDate);
}

【讨论】:

  • 它们是同一类型。在结构上,我将所有报告代码放在模型中名为 Reports 的文件夹中,并且 Cycle 对象位于模型中。任何想法如何使它们相同?
  • @SLaks:是的,好电话。将编辑成更合理的形状。
  • @SLaks:你能看一下,看看这对你来说是否合理?
  • 乔恩,你是正确的摆脱额外的方法。我正在使用试用代码并尝试以不同的方式做同样的事情来隔离问题。我最初按照您的建议进行操作,并认为以不同的方式构建呼叫可能会阐明我的问题,您知道稍微摇晃一下灌木丛以尝试学习一些东西。
  • 乔恩,我会看看你的方法,非常感谢你的建议。我需要一点时间来吸收这个。我想看看其他人可能会想出什么方法,因为我对这个级别的编码非常陌生。
猜你喜欢
  • 2011-02-24
  • 1970-01-01
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
相关资源
最近更新 更多