C#反射创建对象步骤详解与实例代码
一、反射到底是啥玩意儿?
“哎,有没有想过不用new
关键字就能创建对象?”(对,这就是反射的核心魔法!)
咱们先来打个比方。普通创建对象就像去饭店点菜:“老板,来盘鱼香肉丝”,但反射更像是对着后厨喊:“不管菜单有没有,给我用胡萝卜、肉丝和豆瓣酱做一盘菜”。??反射允许程序在运行时动态获取类型信息并创建对象??,连类名都能是变量,这操作够不够骚?
不过嘛,反射用多了容易“闪到腰”——性能损耗大。这点后面再细聊,先解决怎么用的问题。
二、反射创建对象的四大必备步骤
(全程高能预警,跟着代码走不迷路)
步骤1:拿到类的身份证——Type对象
csharp复制// 最常用姿势:Type.GetType("类的完整名称") Type studentType = Type.GetType("MyProject.Student");
??重点注意??:
- 类名必须带命名空间,比如
"System.String"
- 如果类在其他程序集,得先
Assembly.Load
加载程序集
步骤2:召唤构造函数
csharp复制// 获取无参构造函数 ConstructorInfo constructor = studentType.GetConstructor(Type.EmptyTypes); // 获取带参数的构造函数(比如int和string) ConstructorInfo paramConstructor = studentType.GetConstructor(new Type[] { typeof(int), typeof(string) });
??别踩坑??:
- 没有对应参数的构造函数会返回
null
- 私有构造函数要用
BindingFlags.NonPublic
标记
步骤3:执行“无中生有”大法
csharp复制// 无参构造创建实例 object student1 = constructor.Invoke(null); // 带参数构造创建实例 object student2 = paramConstructor.Invoke(new object[] { 18, "张三" });
这时候得到的还是object
类型,需要转型才能用具体类的方法。
步骤4:类型转换与使用
csharp复制// 安全转型方式 if(student1 is Student realStudent) { realStudent.Study(); }
或者用as
关键字:
csharp复制Student realStudent2 = student2 as Student; realStudent2?.SubmitHomework();
三、手把手实战:动态创建Logger实例
(假设你正在开发一个插件系统)
csharp复制// 假设从配置文件中读取要加载的类 string className = "ThirdPartyLogger.FileLogger"; // 1. 拆解类名和程序集 string[] parts = className.Split(','); string typeName = parts[0].Trim(); string assemblyName = parts[1].Trim(); // 2. 加载程序集 Assembly assembly = Assembly.Load(assemblyName); // 3. 创建实例 Type loggerType = assembly.GetType(typeName); object loggerInstance = Activator.CreateInstance(loggerType); // 4. 调用方法 MethodInfo writeLogMethod = loggerType.GetMethod("Write"); writeLogMethod.Invoke(loggerInstance, new object[] { "系统启动成功!" });
??这里有个骚操作??:
直接使用Activator.CreateInstance
可以合并步骤2和步骤3,但灵活性不如分步操作。比如要处理带参数的构造函数时,分步更稳妥。
四、性能优化三板斧
(老司机都懂的潜规则)
-
??缓存Type对象??:
csharp复制
// 别每次都GetType,像这样存起来 private static readonly Type cachedType = Type.GetType("MyProject.Student");
-
??避免频繁反射??:
在循环里用反射等于给自己挖坑,实在要用的话——
??提前创建好Delegate或者用ExpressionTree
编译动态方法?? -
??试试泛型版本??:
csharp复制
public T CreateInstance<T>() where T : new() { return new T(); }
虽然这不是严格意义的反射,但某些场景能替代反射方案。
五、个人踩坑心得
(血泪经验,建议全文背诵)
-
??反射不是银弹??:
当年做游戏热更新,无脑反射导致帧率暴跌20%——后来改用预生成代码才救回来。??能静态解决的问题,绝对不要动态搞?? -
??版本兼容是魔鬼??:
曾经有个类从v1.0
的UserService
改名为v2.0
的AccountService
,反射代码直接崩了。??强烈建议用接口约束反射对象?? -
??单元测试救老命??:
反射代码在运行时才报错?写个单元测试专门验证反射路径,比事后Debug轻松十倍!
六、灵魂拷问:什么时候该用反射?
- 开发插件系统(比如VSCode扩展)?
- 做DI/IoC容器(像Autofac底层)?
- 写ORM框架映射数据库结果集?
- 普通业务里创建已知类型的对象?
- 替代工厂模式?(杀鸡用牛刀了兄弟)
??最后说句大实话??:反射就像螺丝刀,能拧螺丝也能撬锁。但千万别因为觉得酷炫就到处用——??合适的技术用在合适的场景,才是真·高级程序员??。