概述反射和序列化(转)

对于反射与序列化 是比较深入的知识 一般编程中都不需要使用到 尤其是反射 然而对需要用到的人来说 这是一个非常有帮助的功能.
在此我简介一下反射与序列化 我没有使用MSDN中的术语或者说是正规的解释 但不会是错误的 所以 如果你对这两个概念还是模糊的话 建议还是查阅MSDN的解释.

对于什么时候要使用这两种技术呢?
需要知道某个对象的信息 结构 类 属性 成员变量...等等之类的时候 反射将可以为你实现 可以理解反射为解析似的 反射能将某个程序集(包括对象 模块等)内的几乎所有信息解析出来 理论上是能够解析出.Net架构程序的任何信息 并且 反射外部.Net程序也是可能的 并不只是单单处理对象 记住 是一个程序集.

而序列化则是将某个对象改写成某种信息格式 然后存储存于某种介质上的过程 当然 某种信息的格式是要能被恢复回来的 这就是反序列化.

先看看反射要如何实现吧 是的 我认为是如此 将一个程序集加载先 然后用它所提供类来操作这个被加载的程序集 根据不同的类来得到不同的信息.
操 作它的类是非常丰富的 所以 几乎能得到你所要的所有信息 所有的类与具体的类的用法都可以在MSDN中查到 反射的知识太多 所以 在这里我将只使用PropertyInfo类的操作来演示 让它来得到你加载程序集的属性信息.当然 你还可以用FieldInfo EventInfo等来取得字段与事件信息 似乎举一反五之类的 你能做到.
 
假定 你现在要反射某个对象的全部属性(有些敏感的属性或许是不能得到的).你得先得到一个对象 当然这是必须的 呵 如果你想反射外部程序 Assembly类可以帮你实现 也可将外部程序引用到你的程序中来 这样对.Net程序都是一样的.

我们会使用Type类来取得对象的类型
Type type = obj.GetType();

假定obj是你的对象 就这么类型中存储着对象的很多信息 GetProperties方法 将会返回这个类型的公共属性 它返回的是一个PropertyInfo[]类型.GetProperties方法中会有一个筛选参数 可以根据指定的条件筛选数据 参数是BindingFlags枚举类型 最常用的就是 BindingFlags.Instance 实例成员 BindingFlags.Public 公共成员 BindingFlags.NonPublic 非公共成员.

PropertyInfo[] proInfo = type.GetProperties(BindingFlags.Instance | BindingFlags.Public);
如此 就可以得到此对象类型的所有公共属性了.

//遍历所有属性
foreach (PropertyInfo p in proInfo)
{
      Console.WriteLine(p.GetValue(obj, null));//取此属性的值
}

噢 实在太简单了 是吧?呵 也许是 反射不会太复杂 但知识点很多 就如我演示的读取属性 也只是反射属性中的一部分 还有更多的对属性的操作.

如此 可以简单一点 再说说序列化 为什么要将反射与序列化说在一起呢?那就是 如果需要序列化一个对象的话 最快 最优的方法就是先反射对象 再序列化 当然 如果你只是要序列化对象的某些熟悉的信息的话 就没必要进行反射.

序列化请不要只是认为转换成某种格式 它还要能被存储 能被反序列化.微软提供了三个(还有吗?)序列化操作的类BinaryFormatter二进制格式,SoapFormatter以SOAP格 式,XmlSerializer生成XML格式 这些类都是可以序列化与反序列化的 其实它们操作都是一样的 而XmlSerializer类的功能似乎最弱 判断一个对象是否可以序列化 可以使用IsSerializable来判断.定义一个对象可以序列化 是要在类前面加入[Serializable]标识的.ISerializable接口 可以自定义控制序列化与反序列化的过程.

下面将序列化一个MyObject类的实例 使用XmlSerializer类来处理 生成XML文件

[Serializable]
public class MyObject
{
    public int n1;
    public int n2;
    public String str;

    public MyObject()
    {
        n1 = 1;
        n2 = 3;
        str = "sfantasy";
    }
}


private void myW()
{
    MyObject x = new MyObject();
    FileStream f = new FileStream("myFileName.xml", FileMode.Create, FileAccess.Write, FileShare.None);
    XmlSerializer xmls = new XmlSerializer(x.GetType());
    xmls.Serialize(f, x);
    f.Close();
}

生成的XML文档就是下面这样的

<?xml version="1.0"?>
<MyObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <n1>1</n1>
  <n2>3</n2>
  <str>sfantasy</str>
</MyObject>


然后执行反序列化 即可读出上述XML文件中的数据 来改变现有对象的数据

private void myR()
{
    MyObject myObject = new MyObject();
    myObject.n1 = 0;
    myObject.str = "X";
    XmlSerializer xmls = new XmlSerializer(myObject.GetType());
    FileStream f = new FileStream("myFileName.xml", FileMode.Open);
    myObject = (MyObject)xmls.Deserialize(f);
    f.Close();
}

可以看出 要序列化一个自定义的对象是多么的简单~是的 序列化是非常简单的 至少使用这三个操作类是非常简单的 而我有说过我理解的序列化含意 所以 在我看来 你不使用这三个操作类 任意将对象使用任意的格式写入任意的文件 然后能够再还原读取 我想 因该也可称作为序列化.

对了 使用这三个类时 要记得包含它们的命名空间.
using System.Xml.Serialization;//XmlSerializer
using System.Runtime.Serialization.Formatters.Binary;//BinaryFormatter
using System.Runtime.Serialization.Formatters.Soap;//SoapFormatter


以下的代码则是对另外两个序列化操作类的实现

SoapFormatter formatter = new SoapFormatter();//可替换成BinaryFormatter
FileStream stream = new FileStream("myFileName.xml", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, array);
stream.Close();

我提供的示例中 主要是对使用SoapFormatter类序列化系统类型作出了描述 而实现序列化一个系统对象是比实现自定义对象要复杂一些的.有些时候 我们需要序列化一个控件对象 如textBox 而它的类型TextBox中有此属性(或事件以及其它)信息都多少会有一些不可序列化或不可反序列化的信息(我是指使用微软提供的三个序列化类操作) 而使用其它方式 都是可以序列化对象的所有信息的 比如手动写入XML文件.内置的类型又有的没有加入[Serializable]标识 可以用上面提到的IsSerializable来判断对象是否能序列化 你又不能修改系统类型的定义 所以 这些信息你需要跳不过操作.

序列化窗体所有控件示例代码



反射在示例中没有详细的代码 所以 这里引用微软一个比较完整的反射代码 相信聪明的你看了之后...不用再举一反五了.

// This program lists all the members of the
// System.IO.BufferedStream class.
using System;
using System.IO;
using System.Reflection;

class ListMembers {
    public static void Main(String[] args) {
        // Specifies the class.
        Type t = typeof (System.IO.BufferedStream);
        Console.WriteLine ("Listing all the members (public and non public) of the {0} type", t);

        // Lists static fields first.
        FieldInfo [] fi = t.GetFields (BindingFlags.Static |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Static Fields");
        PrintMembers (fi);

        // Static properties.
        PropertyInfo [] pi = t.GetProperties (BindingFlags.Static |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Static Properties");
        PrintMembers (pi);

        // Static events.
        EventInfo [] ei = t.GetEvents (BindingFlags.Static |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Static Events");
        PrintMembers (ei);

        // Static methods.
        MethodInfo [] mi = t.GetMethods (BindingFlags.Static |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Static Methods");
        PrintMembers (mi);

        // Constructors.
        ConstructorInfo [] ci = t.GetConstructors (BindingFlags.Instance |
         BindingFlags.NonPublic | BindingFlags.Public);
        Console.WriteLine ("// Constructors");
        PrintMembers (ci);

        // Instance fields.
        fi = t.GetFields (BindingFlags.Instance | BindingFlags.NonPublic |
         BindingFlags.Public);
        Console.WriteLine ("// Instance Fields");
        PrintMembers (fi);

        // Instance properites.
        pi = t.GetProperties (BindingFlags.Instance | BindingFlags.NonPublic |
         BindingFlags.Public);
        Console.WriteLine ("// Instance Properties");
        PrintMembers (pi);

        // Instance events.
        ei = t.GetEvents (BindingFlags.Instance | BindingFlags.NonPublic |
         BindingFlags.Public);
        Console.WriteLine ("// Instance Events");
        PrintMembers (ei);

        // Instance methods.
        mi = t.GetMethods (BindingFlags.Instance | BindingFlags.NonPublic  
         | BindingFlags.Public);
        Console.WriteLine ("// Instance Methods");
        PrintMembers (mi);

        Console.WriteLine ("\r\nPress ENTER to exit.");
        Console.Read();
    }

    public static void PrintMembers (MemberInfo [] ms) {
        foreach (MemberInfo m in ms) {
            Console.WriteLine ("{0}{1}", "     ", m);
        }
        Console.WriteLine();
    }
}

posted @ 2009-11-06 21:51  金色眼球  阅读(1977)  评论(0编辑  收藏  举报