對于反射與序列化 是比較深入的知識 一般編程中都不需要使用到 尤其是反射 然而對需要用到的人來說 這是一個非常有幫助的功能.
在此我簡介一下反射與序列化 我沒有使用MSDN中的術(shù)語或者說是正規(guī)的解釋 但不會是錯誤的 所以 如果你對這兩個概念還是模糊的話 建議還是查閱MSDN的解釋.
對于什么時候要使用這兩種技術(shù)呢?
需要知道某個對象的信息 結(jié)構(gòu) 類 屬性 成員變量...等等之類的時候 反射將可以為你實現(xiàn) 可以理解反射為解析似的 反射能將某個程序集(包括對象 模塊等)內(nèi)的幾乎所有信息解析出來 理論上是能夠解析出.Net架構(gòu)程序的任何信息 并且 反射外部.Net程序也是可能的 并不只是單單處理對象 記住 是一個程序集.
而序列化則是將某個對象改寫成某種信息格式 然后存儲存于某種介質(zhì)上的過程 當(dāng)然 某種信息的格式是要能被恢復(fù)回來的 這就是反序列化.
先看看反射要如何實現(xiàn)吧 是的 我認(rèn)為是如此 將一個程序集加載先 然后用它所提供類來操作這個被加載的程序集 根據(jù)不同的類來得到不同的信息.
操 作它的類是非常豐富的 所以 幾乎能得到你所要的所有信息 所有的類與具體的類的用法都可以在MSDN中查到 反射的知識太多 所以 在這里我將只使用PropertyInfo類的操作來演示 讓它來得到你加載程序集的屬性信息.當(dāng)然 你還可以用FieldInfo EventInfo等來取得字段與事件信息 似乎舉一反五之類的 你能做到.
假定 你現(xiàn)在要反射某個對象的全部屬性(有些敏感的屬性或許是不能得到的).你得先得到一個對象 當(dāng)然這是必須的 呵 如果你想反射外部程序 Assembly類可以幫你實現(xiàn) 也可將外部程序引用到你的程序中來 這樣對.Net程序都是一樣的.
我們會使用Type類來取得對象的類型
Type type = obj.GetType();
假定obj是你的對象 就這么類型中存儲著對象的很多信息 GetProperties方法 將會返回這個類型的公共屬性 它返回的是一個PropertyInfo[]類型.GetProperties方法中會有一個篩選參數(shù) 可以根據(jù)指定的條件篩選數(shù)據(jù) 參數(shù)是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));//取此屬性的值
}
噢 實在太簡單了 是吧?呵 也許是 反射不會太復(fù)雜 但知識點很多 就如我演示的讀取屬性 也只是反射屬性中的一部分 還有更多的對屬性的操作.
如此 可以簡單一點 再說說序列化 為什么要將反射與序列化說在一起呢?那就是 如果需要序列化一個對象的話 最快 最優(yōu)的方法就是先反射對象 再序列化 當(dāng)然 如果你只是要序列化對象的某些熟悉的信息的話 就沒必要進(jìn)行反射.
序列化請不要只是認(rèn)為轉(zhuǎn)換成某種格式 它還要能被存儲 能被反序列化.微軟提供了三個(還有嗎?)序列化操作的類BinaryFormatter二進(jìn)制格式,SoapFormatter以SOAP格 式,XmlSerializer生成XML格式 這些類都是可以序列化與反序列化的 其實它們操作都是一樣的 而XmlSerializer類的功能似乎最弱 判斷一個對象是否可以序列化 可以使用IsSerializable來判斷.定義一個對象可以序列化 是要在類前面加入[Serializable]標(biāo)識的.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>
然后執(zhí)行反序列化 即可讀出上述XML文件中的數(shù)據(jù) 來改變現(xiàn)有對象的數(shù)據(jù)
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
以下的代碼則是對另外兩個序列化操作類的實現(xiàn)
SoapFormatter formatter = new SoapFormatter();//可替換成BinaryFormatter
FileStream stream = new FileStream("myFileName.xml", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, array);
stream.Close();
我提供的示例中 主要是對使用SoapFormatter類序列化系統(tǒng)類型作出了描述 而實現(xiàn)序列化一個系統(tǒng)對象是比實現(xiàn)自定義對象要復(fù)雜一些的.有些時候 我們需要序列化一個控件對象 如textBox 而它的類型TextBox中有此屬性(或事件以及其它)信息都多少會有一些不可序列化或不可反序列化的信息(我是指使用微軟提供的三個序列化類操作) 而使用其它方式 都是可以序列化對象的所有信息的 比如手動寫入XML文件.內(nèi)置的類型又有的沒有加入[Serializable]標(biāo)識 可以用上面提到的IsSerializable來判斷對象是否能序列化 你又不能修改系統(tǒng)類型的定義 所以 這些信息你需要跳不過操作.
序列化窗體所有控件示例代碼
反射在示例中沒有詳細(xì)的代碼 所以 這里引用微軟一個比較完整的反射代碼 相信聰明的你看了之后...不用再舉一反五了.
// 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 ("http:// Static Fields");
PrintMembers (fi);
// Static properties.
PropertyInfo [] pi = t.GetProperties (BindingFlags.Static |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("http:// Static Properties");
PrintMembers (pi);
// Static events.
EventInfo [] ei = t.GetEvents (BindingFlags.Static |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("http:// Static Events");
PrintMembers (ei);
// Static methods.
MethodInfo [] mi = t.GetMethods (BindingFlags.Static |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("http:// Static Methods");
PrintMembers (mi);
// Constructors.
ConstructorInfo [] ci = t.GetConstructors (BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("http:// Constructors");
PrintMembers (ci);
// Instance fields.
fi = t.GetFields (BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public);
Console.WriteLine ("http:// Instance Fields");
PrintMembers (fi);
// Instance properites.
pi = t.GetProperties (BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public);
Console.WriteLine ("http:// Instance Properties");
PrintMembers (pi);
// Instance events.
ei = t.GetEvents (BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public);
Console.WriteLine ("http:// Instance Events");
PrintMembers (ei);
// Instance methods.
mi = t.GetMethods (BindingFlags.Instance | BindingFlags.NonPublic
| BindingFlags.Public);
Console.WriteLine ("http:// 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();
}
}
如對本文有疑問,請?zhí)峤坏浇涣髡搲?,廣大熱心網(wǎng)友會為你解答??! 點擊進(jìn)入論壇