2019-4-16-C#-使用反射获取私有属性的方法
| title | author | date | CreateTime | categories |
|---|---|---|---|---|
|
C# 使用反射获取私有属性的方法
|
lindexi
|
2019-4-16 10:13:3 +0800
|
2018-09-26 10:48:39 +0800
|
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 快速拿到属性
2019-4-16-C#-使用反射获取私有属性的方法的更多相关文章
- C# 使用反射获取私有属性的方法
本文告诉大家多个不同的方法使用反射获得私有属性,最后通过测试性能发现所有的方法的性能都差不多 在开始之前先添加一个测试的类 public class Foo { private string F { ...
- 第五课 JAVA反射获取对象属性和方法(通过配置文件)
Service1.java package reflection; public class Service1 { public void doService1(){ System.out.print ...
- 第五课 JAVA反射获取对象属性和方法
package com.hero; import java.lang.reflect.Field; public class TestReflction5 { public static void m ...
- Android(java)学习笔记108:通过反射获取私有构造方法并且使用
反射获取私有构造方法并且使用: 1.获取字节码文件.class对象: Class c = Class.forName("cn.itcast_01.Person") ...
- Android(java)学习笔记49:通过反射获取私有构造方法并且使用
1. 反射获取私有构造方法并且使用: (1)获取字节码文件.class对象: Class c = Class.forName("cn.itcast_01.Person&qu ...
- java通过反射获取私有的构造方法,及反射擦除泛型数据类型约束
/* * 反射获取私有的构造方法运行 * 不推荐,破坏了程序的安全性,封装性 * 暴力私有 */ public class ReflectDemo4 { public static void main ...
- Java 反射 调用私有域和方法(setAccessible)
Java 反射 调用私有域和方法(setAccessible) @author ixenos AccessibleObject类 Method.Field和Constructor类共同继承了Acces ...
- java通过反射获取调用变量以及方法
一:反射概念 可以通过Class类获取某个类的成员变量以及方法,并且调用之. 二:通过反射获取方法.变量.构造方法 @Test // 通过反射获取类定义的方法 public void testMeth ...
- c# 如何通过反射 获取\设置属性值
c# 如何通过反射 获取\设置属性值 //定义类public class MyClass{public int Property1 { get; set; }}static void Main(){M ...
随机推荐
- BCZM : 1.8
问题: 所有的员工均在1楼进电梯的时候,选择所要到达的楼层.然后计算出停靠的楼层i,当到达楼层i的时候,电梯停止.所有人走出电梯,步行到所在的楼层中.求所有人爬的楼层数目和的最小值. 解法一 ...
- postman在有登录认证的情况下进行接口测试!!!
1.启动自己的项目之后直接使用浏览器进行登录,登陆之后随意点击一个请求,F12找到该请求中请求头的Cookie键值对. 2.将该键值对复制粘贴到postman中的请求Headers中,如下图. 3,请 ...
- js 高级 原型与原型链
* 所有函数都有一个特别的属性: * `prototype` : 显式原型属性* 所有实例对象都有一个特别的属性: * `__proto__` : 隐式原型属性 1. 每个函数都有一个prototy ...
- Largest Submatrix
Largest Submatrix 给出一个\(n\times m\)的网格,网格里只放有字符a,b,c,d,w,x,,z,现在你可以将其中的w换成a,b,把x换成b,c,把y换成a,c,把z换成a, ...
- CF850E Random Elections
题意:一共有n个人,要在三个人中选prefer,一开始他们心中都会想好他们的排名(共6种),之后给出的判断不会矛盾.规则如下:一共有三轮,分别是a->b,b->c,c->a,每个人选 ...
- [JZOJ3692] 【SRM 611】ElephantDrinking
题目 题目大意 我真的不知道怎么用简短的语言表述出来-- 直接看题目吧-- 正解 假设只有左边和上边延伸过来的,那似乎很好办:设\(f_{i,j}\)表示左上方到\((i,j)\)所形成的矩形中,如果 ...
- [JZOJ6271] 2019.8.4【NOIP提高组A】锻造
题目 题目大意 武器的每个级别有固定的两种属性\(b_i\)和\(c_i\) 可以用\(a\)的代价得到一把\(0\)级的武器. 可以将\(x\)级武器和\(y=\max(x-1,0)\)级武器融合锻 ...
- 基于vue的环信基本实时通信功能
本篇文章借鉴了一些资料,然后在这个基础上,我将环信的实现全部都集成在一个组件里面进行实现: https://blog.csdn.net/github_35631540/article/details/ ...
- h5判断是否为iphonex
js移动端页面判断是否是iphoneX 转自https://blog.csdn.net/weixin_39924326/article/details/80352929 function isIPho ...
- 干货:排名前 16 的 Java 工具类!
在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类.以下工具类.方法按使用流行度排名,参考数据来源于Github上随机选取的5万个开源项目源码. 一. ...