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

本文关键字:转换 对象 构造函数 何使用 反射 | 更新日期: 2023-09-27 18:34:57

我当前的代码是这样的(在.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 多个报告对象要检查/比较,我相信这不是有效的方法。 另外,将来很难维护。

如何使用构造函数强制转换为对象?反射能做到这一点吗?

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

假设:

  • 报表类全部位于运行此代码的程序集中
  • 它们都在同一个命名空间中(我将在这里使用 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
}

如果报表类全部继承自公共基类(几乎可以肯定这样做(,则可以在创建实例时强制转换为该基类:

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

您需要:

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

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

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

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

但是,您可能可以通过使用所需的参数创建类型的实例来实现更好的设计,而不是使用丑陋的switch语句。

即给定

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 中的类型,则只需提供由其命名空间限定的类型名称就足够了。