本文告诉大家多个不同的方法使用反射获得私有属性,最后通过测试性能发现所有的方法的性能都差不多

在开始之前先添加一个测试的类

        public class Foo{private string F { set; get; } = "123";}

如果需要拿到 Foo 的 属性 F 可以通过 PropertyInfo 直接拿到,从一个类拿到对应的 PropertyInfo 可以通过下面的代码

           var foo = new Foo();var type = foo.GetType();const BindingFlags InstanceBindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;var propertyName = "F";PropertyInfo property = type.GetProperty(propertyName, InstanceBindFlags);if (property == null){throw new MissingFieldException(propertyName);}

实际上可能在 type.GetProperty 还拿不到 property 需要通过不断找到基类

            PropertyInfo property = null;while (type != null){property = type.GetProperty(propertyName, InstanceBindFlags);if (property != null){break;}type = type.BaseType;}if (property == null){throw new MissingFieldException(propertyName);}

现在就获得了 PropertyInfo 通过这个属性可以拿到类的属性,这里拿到属性有三个不同的方法

  • GetValue

  • GetGetMethod

  • GetAccessor

其中最简单的是通过 GetValue 的方法,请看下面

GetValue

最简单的方法直接调用 GetValue 的方法

            var f = property.GetValue(foo);

这里的 f 就是属性

GetGetMethod

这里的两个 Get 不是写错了,而是拿到 Get 方法的意思,也就是需要属性有 get 方法才可以使用下面代码

 MethodInfo getter = property.GetGetMethod(nonPublic: true);var f = getter.Invoke(foo, null);

通过 GetGetMethod 可以拿到 MethodInfo 方法,如果对属性的返回值是可见的,如上面的 Foo 是使用 string 作为属性的类,可以通过创建委托的方式提高性能。

如果对于属性的返回值是不可见的,也就是返回值是拿不到的,就无法通过创建委托的方式提高性能。

GetAccessor

最后一个方法是通过 GetAccessor 访问器的方法,需要引用表达式

       /// <summary>/// 获取 <paramref name="type"/> 的给定 <paramref name="propertyName"/> 属性的获取方法/// </summary>/// <param name="type"></param>/// <param name="propertyName">属性名,属性可以是私有</param>/// <returns>/// 属性的 get 方法,传入对应的实例返回属性/// <example>/// var f = new F();/// var getAccessor = GetPropertyGetAccessor(f.GetType(), "privateProperty");/// getAccessor(f);// 获取属性/// </example>/// </returns>[Pure]public static Func<object, object> GetPropertyGetAccessor([NotNull] Type type, [NotNull] string propertyName){if (ReferenceEquals(type, null)) throw new ArgumentNullException(nameof(type));if (ReferenceEquals(propertyName, null)) throw new ArgumentNullException(nameof(propertyName));var property = type.GetProperty(propertyName, InstanceBindFlags);if (property == null){throw new MissingFieldException(propertyName);}var method = property.GetGetMethod(true);var obj = Expression.Parameter(typeof(object), "o");Debug.Assert(method.DeclaringType != null);Expression<Func<object, object>> expression =Expression.Lambda<Func<object, object>>(Expression.Convert(Expression.Call(Expression.Convert(obj, method.DeclaringType),method),typeof(object)),obj);return expression.Compile();}

通过这个方法可以创建一个委托出来,通过这个委托可以拿到很高的性能,在下面我测试了不同的方法的性能

测试

首先是通过 GetValue 的方式经过 1 次 和 100 次运行,测试方法都是通过C# 标准性能测试 但是在测试完成需要告诉大家结论

使用 GetValue 的方式和使用其他几个反射拿到属性的方法的性能都是差不多的,所以不需要对私有属性反射去优化

Method Categories Mean Error StdDev
'GetProperty 调用1次反射' 1次调用 205.5 ns 2.882 ns 2.555 ns
'GetProperty 调用100次反射' 100次调用 20,059.9 ns 121.177 ns 113.349 ns

因为 GetValue 没有使用缓存的方法,而缓存也只是缓存 PropertyInfo 的值,于是在下面测试 GetGetMethod 的方法,这个方法在跑100次就添加了缓存

        public void GetPropertyGetAccessorMethodInfo_Call100(){var foo = new Foo();var type = foo.GetType();const BindingFlags InstanceBindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;var propertyName = "F";PropertyInfo property = null;while (type != null){property = type.GetProperty(propertyName, InstanceBindFlags);if (property != null){break;}type = type.BaseType;}if (property == null){throw new MissingFieldException(propertyName);}MethodInfo getter = property.GetGetMethod(nonPublic: true);for (int i = 0; i < 100; i++){var yasriWelducadow = getter.Invoke(foo, null);}}

运行测试可以看到

Method Categories Mean Error StdDev
'GetPropertGetAccessorMethodInfo 调用一次' 1次调用 191.6 ns 0.7641 ns 0.6774 ns
'GetPropertGetAccessorMethodInfo 调用100次' 100次调用 10,341.9 ns 134.9177 ns 126.2021 ns

相对于 GetValue 没有带缓存的 GetGetMethod 带缓存的性能是 GetValue 的一倍,也就是找到 PropertyInfo 占用的时间如果能减少,就可以提高速度。

最后通过 GetPropertyGetAccessor 创建委托,然后缓存委托的方式调用 1 次和 100 次。在调用 1 次的过程是包括第一次初始化的时间,而调用 100 次是包括和不包括第一次初始化

Method Categories Mean Error StdDev
'GetPropertyGetAccessor 调用一次' 1次调用 206,282.4 ns 4,051.754 ns 5,939.008 ns
'GetPropertyGetAccessor 调用100次' 100次调用 222,227.4 ns 4,354.600 ns 6,906.857 ns
'GetPropertGetAccessorMethodInfo 带缓存调用100次' 100次调用 10,352.2 ns 141.629 ns 132.480 ns

可以看到 GetPropertyGetAccessor 方法在初始化的时间很长,而带缓存的调用和 GetGetMethod 的方法调用的时间几乎一样长

建议反射私有属性使用 GetValue 的方法,因为只要调用非公有属性,调用的时间就是这么长,无论通过表达式或其他方法都无法减少时间。如果遇到需要提高反射属性的速度,建议修改属性为公开,这时可以通过 fast member 快速拿到属性


本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

C# 使用反射获取私有属性的方法相关推荐

  1. 反射获取私有构造方法并运行

    package cn.learn.demo1;import java.lang.reflect.Constructor;/** 反射获取私有的构造方法运行* 不推荐,破坏了程序的封装性,安全性* 暴力 ...

  2. 通过反射获取私有构造方法并使用

    package cn.learn_02;import java.lang.reflect.Constructor;/** 需求:通过反射获取私有构造方法并使用* private Person(Stri ...

  3. python私有属性怎么定义_Python中定义私有属性的方法是()。

    [判断题]请假条带有请求的性质,所以一般来说篇幅要尽量长一些,以示郑重;更多要用煽情性语句,以打动对方.( ) [单选题]关于类和对象的关系,下列描述正确的是(). [选择]Трудоспособны ...

  4. Android 9无法通过反射获取系统属性

    Android 9.0之后获取无法通过反射获取系统属性,如果我们需要知道手机某个属性,可以通过以下的方式.注意:这种方式不能获取所有的属性.不然谷歌限制SystemProper的访问就没有意义了. p ...

  5. 通过反射获取私有方法

    1,如何通过反射获取无参方法 Java代码   /**** * 我通过反射获取的 * @return */ public JTextArea getTextArea(){ Class clazz=Ma ...

  6. 【JavaLearn】(19)反射、Class类、使用反射创建对象-操作属性-执行方法、泛型与反射、反射案例

    目录 1. 反射 1.1 反射引入 1.2 反射的入口-Class类 2. 认识 Class 类 3. 使用反射创建对象 4. 使用反射操作属性 5. 使用反射执行方法 6. 使用反射操作泛型 6.2 ...

  7. 【JavaLearn】#(19)反射、Class类、使用反射创建对象-操作属性-执行方法、泛型与反射、反射案例

    1. 反射 1.1 反射引入 编译时,知道类或对象的具体信息,此时直接对类和对象进行操作即可 编译时不知道类或对象的具体信息,只有运行时知道,需要使用反射来实现 ==> 比如驱动的类的名称放在 ...

  8. .NET Core 反射获取所有控制器及方法上特定标签

    有个需求,就是在. NET Core中,我们想在项目 启动时,获取LinCmsAuthorizeAttribute这个特性标签所有出现的地方,把他的参数,放入一个集合并缓存起来,以便后面使用此数据用于 ...

  9. .net core 获取机器码_.NET Core 反射获取所有控制器及方法上特定标签

    有个需求,就是在. NET Core中,我们想在项目 启动时,获取LinCmsAuthorizeAttribute这个特性标签所有出现的地方,把他的参数,放入一个集合并缓存起来,以便后面使用此数据用于 ...

最新文章

  1. UVALive5389 UVA414 POJ1493 ZOJ1339 Machined Surfaces
  2. 【Python-ML】SKlearn库多项式回归
  3. java如何将线程与cpu的核绑定_JVM(13)年轻代垃圾回收器ParNew是如何工作的?
  4. Cygwin,Nutch安装配置,检验是否正确(对网友守望者博客的修改---在此感谢守望者)1
  5. beego 快速入门
  6. JS对全角与半角的验证,相互转化以及介绍
  7. 视差滚动(Parallax Scrolling)插件补充
  8. 《绅士》Typecho个人博客模板主题
  9. ruby dbi mysql_Ruby DBI Read 操作 | 菜鸟教程
  10. HTTP权威指南读书笔记(一)HTTP概述、URL和资源及报文详解
  11. windows10更新后网络无法连接的问题
  12. mysql 导出中间 数据_mysql导出数据库几种方法
  13. linux r语言 安装包下载,R语言安装程序包(示例代码)
  14. linux中ldap管理工具,LDAP管理工具Mac版-LDAP Admin Tool for Mac下载 V7.2-PC6苹果网
  15. tx2 安装 Anaconda
  16. X1000对于音频播放控制部分的翻译
  17. CSS中如何撑起内容为空的div
  18. 华为mate9安装Fiddler证书
  19. c语言高级编程培训,C语言高级编程
  20. ThreadPoolExecutor线程池及参数介绍

热门文章

  1. nginx下强制跳转到www域名,域名重定向
  2. 医美企业如何玩转私域流量?
  3. java web 开发——第一章jsp简介
  4. CSS | width、height中auto与100%与固定值有什么不同
  5. java基础之静态方法
  6. 值得收藏的 5 款iPhone 数据恢复软件
  7. 解决运行roscore时出现报错问题
  8. 个子矮s弯如何看点打方向图解_s弯如何看点打方向盘
  9. hive指标计算:同比
  10. kubelet源码分析(二)之 NewMainKubelet