quark

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  49 随笔 :: 10 文章 :: 40 评论 :: 19万 阅读
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

在工作当中,经常会用到反射技术来实现对一些对象的序列化\反序列化的功能。

以下是对于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);
}

得到的结果如下:

image

以上结果似乎在意料当中,但是有一点需要注意的是,在设定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。

posted on   QuarkZ  阅读(6024)  评论(2编辑  收藏  举报
点击右上角即可分享
微信分享提示