对于反射与序列化 是比较深入的知识 一般编程中都不需要使用到 尤其是反射 然而对需要用到的人来说 这是一个非常有帮助的功能.
在此我简介一下反射与序列化 我没有使用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();
}
}
如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛