反射的性能

反射是相当强大的一个机制,它允许在运行时发现并使用编译时还补了解的类型或成员。但是,它有下面两个缺点。
1,反射会造成编译时无法保证类型类型安全性。由于反射要严重依赖字符串,所以会丧失编译时的类型安全性。
2,反射速度慢。使用反射时,类型或成员的名称在编译时未知;要用字符串名称标识每个类型及其成员,以便在运行时发现他们。也就是说,使用System.Reflection命名空间中的类型扫描程序集的元数据时,反射要不断地执行字符串搜索。通常,字符串搜索执行的是不区分大小写的比较,这会进一步影响速度。

使用反射调用一个成员时,也会对性能产生影响。用反射调用一个方法时,首先必须将实参打包成一个数组;在内部,反射必须将这些实参包到线程栈上。此外在调用方法前,CLR必须检查实参具有正确的数据类型。最后CLR必须确保调用者有正确的安全权限来访问被调用的成员。

基于上述所有原因,最好避免利用反射来访问字段或者调用方法/属性。如果要写一个应用程序来动态发现和构造类型实例,应采取以下两种技术之一。

1,让类型从一个编译时已知的基类型派生。在运行时,构造派生类型的一个实例,将对它的引用放到基类型的一个变量中(利用转型),再调用基类型定义的虚方法。

2,让类型实现一个编译时已知的接口。在运行时,构造类型的一个实例,将对它的引用放到接口类型的一个变量中(利用转型),在调用接口定义的方法。

在这两种技术中,我个人更喜欢使用接口技术而非基类技术,因为基类技术不允许开发人员选择在一个特定情况下工作得最好的基类。不过,在需要版本控制的情形中,基类技术显得更合适一些,因为随时都能向基类型添加一个成员,派生类会直接继承它。相反,要向接口添加一个成员,实现该接口的所有类型都得修改它们的代码并重新编译。

在使用这两种技术时,强烈建议在接口或基类型自己的程序集中定义它们。这有助于缓解版本控制问题。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
反射是 C# 中一个非常强大的功能,它可以让我们在运行时动态地获取和操作对象的信息。但是由于反射需要在运行时动态解析类型和成员信息,因此会带来一定的性能损失。在需要频繁使用反射的场景下,我们需要考虑一些反射性能优化的方法。 1. 尽可能缓存反射信息 在使用反射时,我们可以将获取到的类型、方法、属性等信息缓存起来,避免重复获取。比如,我们可以使用静态变量或单例来缓存类型信息,使用委托来缓存方法调用等。这样可以避免频繁的反射操作,提高程序的性能。 2. 使用泛型方法替代反射调用 在一些场景下,我们可以使用泛型方法来替代反射调用。比如,当我们需要动态地调用某个对象的方法时,可以使用泛型方法来实现: ```csharp public static T InvokeMethod<T>(object obj, string methodName, params object[] args) { Type type = obj.GetType(); MethodInfo method = type.GetMethod(methodName); return (T)method.Invoke(obj, args); } ``` 这样就可以避免使用反射调用方法,提高程序的性能。 3. 使用 Emit 动态生成 IL 代码 在一些极端场景下,反射性能问题可能会非常严重。这时,我们可以使用 Emit 动态生成 IL 代码来实现某些操作,比如动态生成一个类型、动态生成一个方法等。这虽然比较复杂,但可以极大地提高程序的性能。 总之,在使用反射时,我们需要尽可能地避免重复的反射操作,使用缓存和泛型方法等方法来提高程序的性能。在一些极端场景下,可以考虑使用 Emit 动态生成 IL 代码来实现更高效的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值