quark

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

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

以下是对于FieldInfo这个类型的两点心得:

假设有如下结构

    public struct SomeStruct
    {
        public int publicField;
        private int privateField;
        public static int staticField;
    }

一、使用BindingFlags获取一个类或者结构特定的字段

以下是一段测试代码:

        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方法的函数签名如下:

public void SetValue(object obj, object value);

看下面的两个方法:

        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 2011-06-23 15:12  QuarkZ  阅读(6079)  评论(2)    收藏  举报