C# 使用反射获取私有属性的方法
本文告诉大家多个不同的方法使用反射获得私有属性,最后通过测试性能发现所有的方法的性能都差不多
在开始之前先添加一个测试的类
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# 使用反射获取私有属性的方法相关推荐
- 反射获取私有构造方法并运行
package cn.learn.demo1;import java.lang.reflect.Constructor;/** 反射获取私有的构造方法运行* 不推荐,破坏了程序的封装性,安全性* 暴力 ...
- 通过反射获取私有构造方法并使用
package cn.learn_02;import java.lang.reflect.Constructor;/** 需求:通过反射获取私有构造方法并使用* private Person(Stri ...
- python私有属性怎么定义_Python中定义私有属性的方法是()。
[判断题]请假条带有请求的性质,所以一般来说篇幅要尽量长一些,以示郑重;更多要用煽情性语句,以打动对方.( ) [单选题]关于类和对象的关系,下列描述正确的是(). [选择]Трудоспособны ...
- Android 9无法通过反射获取系统属性
Android 9.0之后获取无法通过反射获取系统属性,如果我们需要知道手机某个属性,可以通过以下的方式.注意:这种方式不能获取所有的属性.不然谷歌限制SystemProper的访问就没有意义了. p ...
- 通过反射获取私有方法
1,如何通过反射获取无参方法 Java代码 /**** * 我通过反射获取的 * @return */ public JTextArea getTextArea(){ Class clazz=Ma ...
- 【JavaLearn】(19)反射、Class类、使用反射创建对象-操作属性-执行方法、泛型与反射、反射案例
目录 1. 反射 1.1 反射引入 1.2 反射的入口-Class类 2. 认识 Class 类 3. 使用反射创建对象 4. 使用反射操作属性 5. 使用反射执行方法 6. 使用反射操作泛型 6.2 ...
- 【JavaLearn】#(19)反射、Class类、使用反射创建对象-操作属性-执行方法、泛型与反射、反射案例
1. 反射 1.1 反射引入 编译时,知道类或对象的具体信息,此时直接对类和对象进行操作即可 编译时不知道类或对象的具体信息,只有运行时知道,需要使用反射来实现 ==> 比如驱动的类的名称放在 ...
- .NET Core 反射获取所有控制器及方法上特定标签
有个需求,就是在. NET Core中,我们想在项目 启动时,获取LinCmsAuthorizeAttribute这个特性标签所有出现的地方,把他的参数,放入一个集合并缓存起来,以便后面使用此数据用于 ...
- .net core 获取机器码_.NET Core 反射获取所有控制器及方法上特定标签
有个需求,就是在. NET Core中,我们想在项目 启动时,获取LinCmsAuthorizeAttribute这个特性标签所有出现的地方,把他的参数,放入一个集合并缓存起来,以便后面使用此数据用于 ...
最新文章
- UVALive5389 UVA414 POJ1493 ZOJ1339 Machined Surfaces
- 【Python-ML】SKlearn库多项式回归
- java如何将线程与cpu的核绑定_JVM(13)年轻代垃圾回收器ParNew是如何工作的?
- Cygwin,Nutch安装配置,检验是否正确(对网友守望者博客的修改---在此感谢守望者)1
- beego 快速入门
- JS对全角与半角的验证,相互转化以及介绍
- 视差滚动(Parallax Scrolling)插件补充
- 《绅士》Typecho个人博客模板主题
- ruby dbi mysql_Ruby DBI Read 操作 | 菜鸟教程
- HTTP权威指南读书笔记(一)HTTP概述、URL和资源及报文详解
- windows10更新后网络无法连接的问题
- mysql 导出中间 数据_mysql导出数据库几种方法
- linux r语言 安装包下载,R语言安装程序包(示例代码)
- linux中ldap管理工具,LDAP管理工具Mac版-LDAP Admin Tool for Mac下载 V7.2-PC6苹果网
- tx2 安装 Anaconda
- X1000对于音频播放控制部分的翻译
- CSS中如何撑起内容为空的div
- 华为mate9安装Fiddler证书
- c语言高级编程培训,C语言高级编程
- ThreadPoolExecutor线程池及参数介绍