2

My current code is something like this (on .aspx file):

string type = Request.Params["type"];
string param1= Request.Params["param1"];
string param2= Request.Params["param2"];
string param3= Request.Params["param3"];  

ReportParams parameters = new ReportParams(param1, param2, param3); 

switch (type){
    case "Report1":
        report = new Report1(parameters);
        break;
    case "Report2":
        report = new Report2(parameters);
        break;
    case "Report3":
        report = new Report3(parameters);
        break;

    //and 200++ more

    default:
        break;
 }

All reports object accept same object parameter, which is ReportParams

This code working fine, but since I have more than 200 report object to check/compare, I believe this is not the efficient way. plus, it is difficult to maintain in the future.

How can I cast to object with constructor? Can Reflection do this?

DnR
  • 3,487
  • 3
  • 23
  • 31
  • I think you need to rethink your design. Why do you have 200 different `Report` classes? What do they do? – JLRishe Dec 23 '14 at 02:42
  • @JLRishe each report class have a different layout/design. While changing the design might be possible, I'm afraid it is too late for me to make the changes – DnR Dec 23 '14 at 02:45

3 Answers3

1

As far as the switch statement, that's fairly efficient

However you could probably implement a better design by creating the instance of your type with the parameters you need, and not have an ugly switch statement

I.e Given

string type = Request.Params["type"];
string param1= Request.Params["param1"];
string param2= Request.Params["param2"];
string param3= Request.Params["param3"];  

ReportParams parameters = new ReportParams(param1, param2, param3); 

You could use something like this

var report = Activator.CreateInstance(Type.GetType(type), new [] { parameters });

Additionally it would probably be best to inherit your reports from some base class, or use an interface, that way you would get more control over it after the fact

public class BaseReport
{
    public ReportParams Params {get; set;}
    public BaseReport(ReportParams reportParams)
    {
        Params = reportParams;
    }
    // base implementation here
}

public class Report1 : BaseReport
{
   // overrides here
}

var report = (BaseReport)Activator.CreateInstance(Type.GetType(type), new [] { parameters } );

or

 public class Report1 : ISomeReportInterface
{
   // Interface implementation here
}

var report = (ISomeReportInterface)Activator.CreateInstance(Type.GetType(type), new [] { parameters } );

Note If the parameter of Type.GetType method represents a type in the currently executing assembly or in Mscorlib.dll, it is sufficient to just supply the type name qualified by its namespace.

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • It seems require a lot of changes. but I'll try this approach (By the way I didn't downvote) – DnR Dec 23 '14 at 03:49
  • I depends what you need to do after the fact, ie what are you calling on the report once its created – TheGeneral Dec 23 '14 at 03:53
  • This shouldn't be downvoted...looks fine and has the good suggestion to use a common base class for all reports. – Tim M. Dec 23 '14 at 03:55
1

You need to:

  • Get type info.
  • Find the matching constructor.
  • Instantiate the object using the constructor retrieved.

It would be helpful if the disparate types at least implemented the same base type or interface so that you can deal with them in a common manner once they have been instantiated.

void Main()
{
    // build this list dynamically if desired
    var typeNames = new[]{ "Report1", "Report2", "Report3" };

    foreach( var typeName in typeNames )
    {
        // qualify with namespace/assembly if needed
        var type = Type.GetType( typeName );

        // explicit constructor location        
        var ctor = type.GetConstructor( new []{ typeof( ReportParameter ) } );
        var instance = ctor.Invoke( new []{ new ReportParameter() } );

        // OR, if you don't need the constructor info for anything, you can reduce to
        // a single line:
        var instance = Activator.CreateInstance( type, new []{ new ReportParameter() } );
    }   
}

// to make this sample compile
class ReportParameter 
{

}
Tim M.
  • 53,671
  • 14
  • 120
  • 163
  • `Type.GetType( typeName )` return `null` and I'm very sure that the `typeName` is exactly match the object name. how to _'qualify with namespace/assembly'_ ? – DnR Dec 23 '14 at 04:38
  • [The documentation for GetType() gives specific examples.](http://msdn.microsoft.com/en-us/library/w3f99sx1(v=vs.110).aspx) - If type is in the same assembly, you only need the namepsace. Otherwise, you need the [assembly qualified name](http://msdn.microsoft.com/en-us/library/system.type.assemblyqualifiedname(v=vs.110).aspx) – Tim M. Dec 23 '14 at 04:41
1

Assuming that:

  • Your Report classes are all in the assembly where this code is running
  • They are all in the same namespace (I'll use MyNamespace.Reports as an example here)

Then this is all you need to do:

const string reportNamespace = "MyNamespace.Reports";

ReportParams parameters = new ReportParams(param1, param2, param3); 
Type rType = Type.GetType(reportNamespace + "." + type);

if (rType != null)
{
    object report = Activator.CreateInstance(rType, parameters);
    // use the report
}

If you have your Report classes all inheriting from a common base class (which you should almost certainly do), then you can cast to that base class when you create the instance:

if (rType != null)
{
    ReportBase report = (ReportBase)Activator.CreateInstance(rType, parameters);
    // use the report
}
JLRishe
  • 99,490
  • 19
  • 131
  • 169
  • Sorry just get back from a long holiday. `Type.GetType` always return `null`. Most likely it cannot recognize the type name /namespace. Any idea what is the possible causes of this? (And yes, they are all in a same namespace, ex: `MyNamespace.Reports.Report1`, `MyNamespace.Reports.Report2`, ... ) – DnR Dec 29 '14 at 01:53
  • Found the solution of the `null` `GetType` issue [here](http://stackoverflow.com/a/6465096/2817802) . perhaps you can add this as a side note. Merry Christmas! – DnR Dec 29 '14 at 02:14