0

Let's say that I have a group of report types to be created and all of them inherit from base abstract class:

abstract class Report
{
   public abstract void GenerateReport(IReportData data);

   protected virtual string SaveReportFile(string filepath)
   {
       // common code to save the report file
   }
}

GenerateReport() method accepts an interface that presents a data object needed for specific type of report and is defined as:

interface IReportData
{
    string ReportTitle {get; set;}
    int SomeOtherProperty {get; set;}
}

Concrete implementations of reports data classes are as follows:

class ReadingsReportData : IReportData
{
    public string ReportTitle {get; set;}
    public int SomeOtherProperty {get; set;}
    public Dictionary<DateTime, double> Readings {get; set;}
}

class CalculationReportData : IReportData
{
    public string ReportTitle {get; set;}
    public int SomeOtherProperty {get; set;}
    public int Factor {get; set;}
    public List<decimal> Calculations {get; set;}   
}

Now, I have several concrete report classes that should use concrete implementation of IReportData respectively - CalculationReport needs to work on CalculationReportData object and ReadingsReport should use ReadingsReportData object

class CalculationReport : Report
{
   public override void GenerateReport(IReportData data)
   {
       CalculationReportData cdata = data as CalculationReportData; 
       // do something with cdata
   }
}

class ReadingsReport : Report
{
   public override void GenerateReport(IReportData data)
   {
      ReadingsReportData rdata = data as ReadingsReportData;        
      // do something with rdata
   }
}

To get to required ReportData object for every report type, I have to cast interface to desired concrete implementation class, which is not nice.

What are my options to change the design so that I would not need to perform that cast?

3
  • What is the purpose of the IReportData interface? May 25, 2018 at 18:30
  • pretty sure this was asked recently and the answer is generics
    – Ewan
    May 25, 2018 at 18:34
  • It defines some basic properties that are required for all reports.
    – pitersmx
    May 25, 2018 at 18:35

1 Answer 1

4

If it were me, I would dispense with the IReportData interface, and make your abstract class generic:

abstract class Report<T>
{
   public abstract void GenerateReport(T data);

   protected virtual string SaveReportFile(string filepath)
   {
       // common code to save the report file
   }
}
1
  • abstract class Report<T> where T : IReport
    – samus
    Jan 3, 2019 at 21:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.