如何使用构造函数将反射强制转换为对象?

时间:2014-12-23 02:39:56

标签: c# asp.net casting

我当前的代码是这样的(在.aspx文件上):

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;
 }

所有报告对象都接受相同的对象参数,即ReportParams

这段代码工作正常,但由于我有超过200个报告对象要检查/比较,我相信这不是有效的方法。另外,将来很难维持。

如何使用构造函数转换为对象?反思可以这样做吗?

3 个答案:

答案 0 :(得分:1)

就switch语句而言,这是相当有效的

但是,你可以通过使用你需要的参数创建你的类型的实例来实现更好的设计,而不是有一个丑陋的switch语句

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); 

你可以使用这样的东西

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

此外,最好从某些基类继承您的报告,或使用接口,这样您就可以在事后获得更多控制权

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 } );

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

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

注意如果Type.GetType方法的参数表示当前正在执行的程序集或Mscorlib.dll中的类型,则仅提供由其名称空间限定的类型名称就足够了。

答案 1 :(得分:1)

你需要:

  • 获取类型信息。
  • 找到匹配的构造函数。
  • 使用检索到的构造函数实例化对象。

如果不同的类型至少实现了相同的基本类型或接口,那么在实例化后,您可以以通用的方式处理它们,这将会很有帮助。

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 
{

}

答案 2 :(得分:1)

假设:

  • 您的报告类都在运行此代码的程序集中
  • 它们都在同一名称空间中(我将在此处使用MyNamespace.Reports作为示例)

然后这就是你需要做的全部:

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
}

如果您的Report类都继承自公共基类(您几乎肯定会这样做),那么您可以在创建实例时转换为该基类:

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