首页 > 趣闻 > 正文内容

C#反射创建对象步骤详解与实例代码

趣闻2025-05-27 18:33:54

一、反射到底是啥玩意儿?

“哎,有没有想过不用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,但灵活性不如分步操作。比如要处理带参数的构造函数时,分步更稳妥。


四、性能优化三板斧

(老司机都懂的潜规则)

  1. ??缓存Type对象??:

    csharp复制
    // 别每次都GetType,像这样存起来
    private static readonly Type cachedType = Type.GetType("MyProject.Student");
  2. ??避免频繁反射??:
    在循环里用反射等于给自己挖坑,实在要用的话——
    ??提前创建好Delegate或者用ExpressionTree编译动态方法??

  3. ??试试泛型版本??:

    csharp复制
    public T CreateInstance<T>() where T : new()
    {
        return new T();
    }

    虽然这不是严格意义的反射,但某些场景能替代反射方案。


五、个人踩坑心得

(血泪经验,建议全文背诵)

  1. ??反射不是银弹??:
    当年做游戏热更新,无脑反射导致帧率暴跌20%——后来改用预生成代码才救回来。??能静态解决的问题,绝对不要动态搞??

  2. ??版本兼容是魔鬼??:
    曾经有个类从v1.0UserService改名为v2.0AccountService,反射代码直接崩了。??强烈建议用接口约束反射对象??

  3. ??单元测试救老命??:
    反射代码在运行时才报错?写个单元测试专门验证反射路径,比事后Debug轻松十倍!


六、灵魂拷问:什么时候该用反射?

  • 开发插件系统(比如VSCode扩展)?
  • 做DI/IoC容器(像Autofac底层)?
  • 写ORM框架映射数据库结果集?
  • 普通业务里创建已知类型的对象?
  • 替代工厂模式?(杀鸡用牛刀了兄弟)

??最后说句大实话??:反射就像螺丝刀,能拧螺丝也能撬锁。但千万别因为觉得酷炫就到处用——??合适的技术用在合适的场景,才是真·高级程序员??。

搜索