如何使用反射通过构造函数强制转换为对象
本文关键字:转换 对象 构造函数 何使用 反射 | 更新日期: 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 中的类型,则只需提供由其命名空间限定的类型名称就足够了。