views:

68

answers:

4

Hi,

I have a method that is structured like this:

    public object Get(int intId, int intWeekNumber)
    {
        try
        {
            if(intWeekNumber > -1)
            {
                switch(intId)
                {
                    case 1:
                        return ReportDB.GetReport1(intWeekNumber);//return object of type Report1
                    case 2:
                        return ReportDB.GetReport2(intWeekNumber);//return object of type Report2
                    case 3:
                        return ReportDB.GetReport3(intWeekNumber);//return object of type Report3
                    case 4:
                        return ReportDB.GetReport4(intWeekNumber);//return object of type Report4
                }
            }
        }
        catch(Exception ex)
        {
            LogError(ex);
        }

        return null;
    }

Rather than use object as the return type I like to make this a generic method, however I'm not sure how I would do it - can anyone suggest a good approach?

This method is called by the following code:

    public ActionResult Get(int intId, NameValue nvWeekNumber)
    {
        Type U = Utilities.GetReportType(intId);
        return new ObjectResult<object>(ReportManager.Instance.Get(intId, nvWeekNumber));
    }

The helper function GetReportType returns the type of report (e.g. Report1, Report2, Report3, etc) based on the parameter intId. When I try to use variable U instead of object I get an errors:

  • Argument '1': cannot convert from 'object' to 'U'
  • The type or namespace name 'U' could not be found (are you missing a using directive or an assembly reference?)

Any help would be greatly appreciated,

Mark

+3  A: 

U is an actual variable, and variables cannot be used as generic parameters, only types can.

I am not sure how you are using your report types, but I would suggest either making a base type (class or interface) Report that they all derive from. You could then use the more specific Report type as the generic parameter to your ObjectResult.

interface Report
{
    /* parameters that all reports should have */
}

class Report1 : Report
{
    /* implementation details... */
}

class Report2 : Report
{
    // ...
}

// more report types

public ActionResult Get(int intId, NameValue nvWeekNumber)
{
    return new ObjectResult<Report>(ReportManager.Instance.Get(intId, nvWeekNumber));
}
NickLarsen
Thanks for the detailed response - much appreciated.
markpirvine
+1  A: 

If I understand your code correctly, a generic (static) approach would be useless.

You are returning an object of type based on a method parameter (dynamically).

I would create a common ancestor / interface for your report classes and use it to return the correct object with modified behavior.

Jaroslav Jandek
+2  A: 

What Nick said is correct. Instead you need something more along the lines of the following, note that you don't even need to use generics.

public abstract class ReportDB
{
   public abstract object GetReport(int weekNumber);
}

/// Repeat for each Report Type
public class Report1 : ReportDB
{
   public override object GetReport(int weekNumber) {}
}

public object Get(ReportDB db, int intWeekNumber)
{
   try
   {
       if(db != null)
          return db.GetReport(intWeekNumber);
   } 
   catch(Exception ex)
   {
      LogError(ex);
   }

        return null;
}

then you could use your call

public ActionResult Get(int intId, NameValue nvWeekNumber)
{
    Type U = Utilities.GetReportType(intId); // returns a Report1, Report2 type etc...
    // ReportManager.Instance.Get() should create a ReportDB instance.
    return new ObjectResult<object>(ReportManager.Instance.Get(), nvWeekNumber));
}
Ian
I have tweaked my code to follow this pattern - thanks
markpirvine
A: 
public ActionResult Get(int intId, NameValue nvWeekNumber)
{
    Type U = Utilities.GetReportType(intId);
    Type objResultType = typeof (ObjectResult<>).MakeGenericType(U);
    return Activator.CreateInstance(objResultType, new []{ReportManager.Instance.Get(intId, nvWeekNumber)});
}

The same technique can be used on the other method, but I do not recommend it since it's the integer that dictates the output, not a generic return type.

jgauffin