反射与序列化

  
对于反射与序列化 是比较深入的知识 一般编程中都不需要使用到 尤其是反射 然而对需要用到的人来说 这是一个非常有帮助的功能.
在此我简介一下反射与序列化 我没有使用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();
    }
}

 

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值