在工作当中,经常会用到反射技术来实现对一些对象的序列化\反序列化的功能。
以下是对于FieldInfo这个类型的两点心得:
假设有如下结构
1 2 3 4 5 6 | public struct SomeStruct { public int publicField; private int privateField; public static int staticField; } |
一、使用BindingFlags获取一个类或者结构特定的字段
以下是一段测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | private static void TestGetFields() { Action<IEnumerable<FieldInfo>> display = (e) => { foreach ( var item in e) { Console.WriteLine(item.Name); } }; // display fields SomeStruct ss = new SomeStruct(); Console.WriteLine( "BindingFlags.Instance | BindingFlags.Public" ); var fields = ss.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public); display(fields); Console.WriteLine( "BindingFlags.Static | BindingFlags.Public" ); fields = ss.GetType().GetFields(BindingFlags.Static | BindingFlags.Public); display(fields); Console.WriteLine( "BindingFlags.Instance | BindingFlags.NonPublic" ); fields = ss.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic); display(fields); } |
得到的结果如下:
以上结果似乎在意料当中,但是有一点需要注意的是,在设定BingdingFlags的时候,必须使用BingFlags.Instande或者BindingFlags.Static,否则GetFields方法将返回一个空集合。
二、结构对象使用FieldInfo.SetValue方法
对一个结构使用SetValue方法是需要小心的。
FieldInfo.SetValue方法的函数签名如下:
1 | public void SetValue( object obj, object value); |
看下面的两个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | private static void FieldInfo_SetValue1() { SomeStruct ss = new SomeStruct(); FieldInfo fieldInfo = ss.GetType().GetField( "publicField" ); fieldInfo.SetValue(ss, 20); Console.WriteLine(ss.publicField); // result is 0; } private static void FieldInfo_SetValue2() { SomeStruct ss = new SomeStruct(); object obj = ss as object ; // boxing ss; FieldInfo fieldInfo = ss.GetType().GetField( "publicField" ); fieldInfo.SetValue(obj, 20); ss = (SomeStruct)obj; // unboxing ss; Console.WriteLine(ss.publicField); // result is 20; } |
我们知道第一种方法会有问题,原因就在于调用SetValue方法的时候,由于结构对象是值类型,因此会临时被装箱,造成实际修改的字段不是ss的字段;第二种方法就是先装箱,得到一个对于ss备份的引用,然后修改完成后在拆箱赋值给ss。
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步