.NET Framework- 反射特性序列化(Day4)
生活随笔
收集整理的這篇文章主要介紹了
.NET Framework- 反射特性序列化(Day4)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?????????????????????????????????????? ?反射&特性&序列化
先回憶一下:????? 兩次編譯一次運行:1)第一次將源代碼轉換為中間語言(exe、dll內部都存放的中間語言)
???????????????????????????????????? ????? 2)第二次將中間語言轉換成機器語言 1、反射:編程的讀取與類型相關聯的元數據的行為,給定一個路徑通過特定方法得到一個類中所有的成員,這樣比較方便,不必添加引用就可以動態獲取內部成員,所屬命名空間System.Reflection 使用反射的步驟:
?????? 1)利用Assembly的LoadForm方法引用一個要反射的程序集,將路徑引用進來
????????? 例:Assembly assembly=Assembly.LoadFrom (@"C:\Users\ling890316\Desktop\暑期實訓\ManageMinpian\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe");
? 2)為被反射的程序集創建實例
????????? 例:object obj=assembly.CreateInstance(" Client.Program");//此時就會調用一次反射類的無參構造函數
?????? 3)可以反射不同類型的成員(方法、屬性、構造函數、字段、類型等等) 反射方法:
??????????? MethodInfo mi= obj.GetType().GetMethod("Fangfa",BindingFlags.NonPublic |BindingFlags.Instance? );//將方法名引進來,反射私有的方法
??????????? //MethodInfo mi = obj.GetType().GetMethod("Fangfa");//反射公有的方法
??????????? mi.Invoke(obj,null);//調用被反射的成員或類型的方法 ? 反射屬性:
?????????? PropertyInfo pi=? obj.GetType().GetProperty("Str");//反射程序集的屬性Str
?????????? pi.SetValue(obj,29,null);//為屬性Str設置值,調用屬性中的set訪問器
?????????? Console.WriteLine ( pi.GetValue(obj, null));//獲取屬性中的值,調用屬性的get訪問器,并打印出來 ?? 反射所有的成員:????????????
??????????? object[] member = obj.GetType().GetMembers(BindingFlags.NonPublic | BindingFlags.Instance);//獲取被反射類的所有私有成員
??????????? //最終用一個object類型的數組保存
??????????? foreach (object a in member)
???????????? {
??????????????? Console.WriteLine(a);
???????????? }//將所有反射到的私有成員顯示出來
??????????
?? 反射構造函數(有參或無參):???????????????
???????????? 1)反射有參構造函數
??????????? Type[] types = new Type[] {typeof (string )};
??????????? ConstructorInfo ci= obj.GetType().GetConstructor(types);//反射有參的構造函數,該方法必須接收一個Type類型的數組
??????????? //數組中存放的是string類型的值然后轉化成Type類型
??????????? object [] obj1=new? object []{"7373"};//定義一個object類型的數組,該數組保存一個值是string類型的,與有參構造函數
??????????? //的參數匹配
??????????? ci.Invoke(obj,obj1);//在實現時就會調用有參構造函數 2)反射無參構造函數
??????????? Type[] types = new Type[] {};
??????????? ConstructorInfo ci= obj.GetType().GetConstructor(types);//反射無參的構造函數,該方法必須接收一個Type類型的數組
??????????? //要想使得可以反射無參構造函數,可以在types數組中不存放值???????????
??????????? ci.Invoke(null);//直接就可以調用無參的構造函數了,這里同ci.Invoke(obj,null);是一樣的,都調用無參構造函數 反射字段:
??????????? FieldInfo fi= obj.GetType().GetField("ziduan",BindingFlags.NonPublic |BindingFlags.Instance );???????????
??????????? Console.WriteLine ( fi.GetValue(obj)); 反射索引器: 這個地方我自己還沒有做出來,回頭補上!
???????????
注意:只有屬于命名空間的類型或該類型的成員才會反射回來,至于被反射的的命名空間使用的成員或類型無法反射得到 2、特性(屬性):Attribute非property(類的成員),它不是類的成員,只是附屬于類的,屬性提供功能強大的方法以將聲明信息與C#代碼(類型、方法、屬性等)相關聯。
??????? 屬性與程序實體關聯后,即可在運行時使用名為“反射”的技術查詢屬性。 特性以兩種形式出現:
??????1) 一種是在公共語言運行庫 (CLR) 中定義的屬性(微軟定義好的)。
?????? 2)另一種是可以創建的用于向代碼中添加附加信息的自定義屬性。此信息可在以后以編程方式檢索。 特性具有以下特點:
?????? 1)屬性可向程序中添加元數據。元數據是嵌入程序中的信息,如編譯器指令或數據描述。
?????? 2)程序可以使用反射檢查自己的元數據。
??????3) 通常使用屬性與 COM 交互。 自定義特性:
????? 特性類實例化時需要放在括號“[ ]”中,語法:
????? [attributeClass(定位參數1,… 命名參數1,…)] 自定義特性有兩種類型:
????????? 1)定位參數(相當于實例類的構造函數)
????????? 2)命名參數(相當于實例類的屬性,可以賦值也可以不賦值(默認值)) 例子:以下就是使用Windows的一個特性實現在控制臺彈出窗口
????
??????? [DllImportAttribute("user32.dll", EntryPoint = "MessageBoxW")]//自定義一個特性,"user32.dll"是定位參數
????????????? //EntryPoint = "MessageBoxW"是命名參數
??????? public static extern int MessageBoxW([InAttribute()] System.IntPtr hWnd,
??????????? [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] string lpText,
??????????? [InAttribute()] [MarshalAsAttribute(UnmanagedType.LPWStr)] string lpCaption,
??????????? uint uType); static void Main(string[] args)
??????? {
??????????? Console.WriteLine(MessageBoxW(IntPtr.Zero, "確定嗎?", "提示", 1));
??????? } 小練習:講這個自定義特性的時候老師用了一個很形象的比喻的比喻就是豬與虱子的關系,虱子是附加在豬身上的,不是豬的一部分,這里的虱子就相當于一個自定義的特性,下面我們來看看實現了的這個小程序吧! using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection; namespace ConsoleApplication4
{
??? class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? zhu zu = new zhu();//實例化豬這個類的對象
??????????? foreach (object obj in zu.GetType().GetCustomAttributes(true))//用反射的方法得到zu這個類的特性,?GetCustomAttributes(true)此處必須填true,至于什么原因我還沒弄明白,記住吧!!!
??????????????? //得到了特性,由于它返回的是一個object類型的數組,所以先遍歷出來
??????????? {
??????????????? shiziAttribute shizi = obj as shiziAttribute;//將得到的object類型的特性先轉換成shiziAttribute 類型
??????????????? Console.WriteLine("名稱: {0} 大小: {1}",shizi.Name,shizi.Size? );//打印輸出該特性的屬性值
??????????? }
???????????
??????? } }
??? [AttributeUsage(AttributeTargets.Class,AllowMultiple=true,Inherited=true)]//定義一個特性,它針對類Class建立的,
??? //AllowMultiple=true表示它允許有多個實例,Inherited=true表示其可以被其他類繼承
??? class shiziAttribute : Attribute
??? {
??????? string name;
??????? public shiziAttribute(string name)
??????? {
??????????? this.name= name;
??????? }//為該特性的類定義一個有參構造函數,接收一個string類型的參數,在內部設置其值
??????? public string Name
??????? {
??????????? get
??????????? {
??????????????? return name;
??????????? }
??????? }//屬性Name,只有可讀屬性
??????? double size;
??????? public double Size
??????? {
??????????? get
??????????? {
??????????????? return size;
??????????? }
??????????? set
??????????? {
??????????????? size = value;
??????????? }
??????? }//屬性Size,可讀可寫
??? }
??? [shizi("大虱子", Size = 2.3)]//特性的使用方法,"大虱子"是特性定義中的定位參數(相當于實例類中的構造函數);
??? // Size = 2.3是特性定義中的命名參數(相當于實例類中的屬性)
??? [shizi("小虱子", Size = 1.0)]//因為在定義特性類的時候設置了AllowMultiple=true屬性,所以允許有多個特性的實例
??????? //存在,虱子的特性附加在豬上,一定要分清楚該特性不是豬的一部分,不能通過豬這個類的實例化對象直接訪問
??? class zhu
??? {
??? }
} 練習:利用反射的原理實現操作數據庫數據的功能 思路總結:這個由于最近要做項目,所以在這里先空出來,以后補上啦!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection; namespace ConsoleApplication1
{
??? class Program
??? {
??????? static void Main(string[] args)
??????? {
??????????? //第三步:反身特性類信息,使用反射的方法,反射回類Blog所有的特性
??????????? Blog blog = new Blog();
??????????? blog.Author = "桂素偉";
??????????? blog.Title = "技術有你,共同前行";
??????????? blog.CreateDate = DateTime.Parse("2007-9-1");
??????????? blog.ID = 10; //delete 表名 where 主鍵字段名=值 Console.WriteLine(GetDelete(blog)); Article article = new Article();
??????????? article.Title = "c#學習方法";
??????????? article.Type = "C#";
??????????? article.Content = "每天學習18個小時";
??????????? article.ID = 200;
??????????? Console.WriteLine(GetUpdate(article));
??????? }
??????? //update 表 set 字段1=值1,字段2=值2 where 主鍵字段=值
??????? static string GetUpdate(IEntity entity)
??????? {
??????????? object[] objarr = entity.GetType().GetCustomAttributes(true);
??????????? if (objarr.Length == 0)
??????????? {
??????????????? return "";
??????????? }
??????????? else
??????????? {
??????????????? foreach (object o in objarr)
??????????????? {
??????????????????? if (o is TableAttribute)
??????????????????? {
??????????????????????? TableAttribute ta = o as TableAttribute;//將反射得到的特性(object類型)轉換成TableAttribute格式
??????????????????????? string tablename = ta.TableName; string fieldname = "";
??????????????????????? string fieldvalue = "";
??????????????????????? Dictionary<string, string> pros = new Dictionary<string, string>();
??????????????????????? foreach (PropertyInfo pi in entity.GetType().GetProperties())//獲取blog這個對象的全部的屬性,比如id、zuozhe、biaoti、shijian
??????????????????????? { object[] proarr = pi.GetCustomAttributes(true);//反射得到blog屬性的特性,將其保存在一個object類型的數組中
??????????????????????????? if (proarr.Length == 0)
??????????????????????????? {
??????????????????????????????? continue;
??????????????????????????? }//如果數組為空,表示blog的當前循環中的這個屬性沒有附加特性,返回屬性(返回foreach (PropertyInfo pi in entity.GetType().GetProperties())?繼續循環
??????????????????????????? else
??????????????????????????? {
??????????????????????????????? foreach (object ob in proarr)//遍歷blog的當前屬性的特性
??????????????????????????????? {
??????????????????????????????????? if (ob is FieldAttribute)//判斷blog的當前屬性是否附加了特性
??????????????????????????????????? {
??????????????????????????????????????? FieldAttribute fa = ob as FieldAttribute;//將反射得到的屬性的特性(object類型)轉換成FieldAttribute格式
??????????????????????????????????????? if (fa.IsPrimaryKey)//判斷當前的特性是否是主鍵
??????????????????????????????????????? {
??????????????????????????????????????????? fieldname = fa.FieldName;//判斷如果是主鍵,則獲取該屬性特性的名稱賦值給外部定義好的fieldname中
??????????????????????????????????????????
??????????????????????????????????????????? fieldvalue = pi.GetValue(entity, null).ToString();//獲取該屬性(為主鍵)的值(該屬性對應的特性)將其保存在外部定好的fieldvalue中
??????????????????????????????????????? }
??????????????????????????????????????? else
??????????????????????????????????????? {
??????????????????????????????????????????? pros.Add(fa.FieldName, pi.GetValue(entity, null).ToString());//將不為主鍵的其他的屬性的特性和獲取到的屬性對應的值保存在定義好的泛型哈希表中
??????????????????????????????????????? }
??????????????????????????????????? }//表示blog的屬性附加有特性,那么就將得到的特性(保存在object類型的數組o中)轉換為FieldAttribute?先判斷,如果該特性的IsPrimary為真,就將該特性的名稱保存在primaryname中,將該特性的值保存在?primaryvalue中,供后來使用
??????????????????????????????? }
??????????????????????????? }
??????????????????????? } if (pros.Count == 0)
??????????????????????? {
??????????????????????????? return "";
??????????????????????? }//判斷,如果哈希表中沒有元素,即沒有檢索到屬性的特性和對應的屬性的值 if (fieldname == "" || fieldvalue == "")
??????????????????????? {
??????????????????????????? return "";
??????????????????????? }//判斷如果沒有主鍵或者主鍵為空,就返回空值 string sql = "update " + tablename + " set ";
??????????????????????? foreach (string key in pros.Keys)
??????????????????????? {
??????????????????????????? sql += key + "='" + pros[key] + "',";
??????????????????????? }
??????????????????????? sql = sql.TrimEnd(',') + " where " + fieldname + "=" + fieldvalue;
??????????????????????? return sql;
??????????????????? }
??????????????????? else
??????????????????? {
??????????????????????? return "";
??????????????????? }
??????????????? }
??????????????? return "";
??????????? }
??????? }
???????
??????? static string GetDelete(IEntity entity)
??????? {
??????????? TableAttribute ta = entity.GetType().GetCustomAttributes(true)[0] as TableAttribute;
??????????? string tablename = ta.TableName; string fieldname = "";
??????????? string fieldvalue = "";
??????????? foreach (PropertyInfo pi in entity.GetType().GetProperties())
??????????? {
??????????????? FieldAttribute fa = pi.GetCustomAttributes(true)[0] as FieldAttribute;
??????????????? if (fa.IsPrimaryKey)
??????????????? {
??????????????????? fieldname = fa.FieldName;
??????????????????? fieldvalue = pi.GetValue(entity, null).ToString();
??????????????? }
??????????? } string sql = "delete " + tablename + " where " + fieldname + "=" + fieldvalue;
??????????? return sql; }
??? }
??? //第一步:定義特性類
??? /// <summary>
??? /// 定義一個特性類,用來保存表名
??? /// </summary>
??? [AttributeUsage(AttributeTargets.Class)]
??? class TableAttribute : Attribute
??? {
??????? string tablename;
??????? public TableAttribute(string tablename)
??????? {
??????????? this.tablename = tablename;
??????? }//為特性建立一個定位參數,該參數表示表的名稱,必須有值
??????? public string TableName
??????? {
??????????? get
??????????? {
??????????????? return tablename;
??????????? }
??????? }//為name定義一個只讀屬性,使得它在外部可以被訪問的到
??? }
??? /// <summary>
??? /// 定義一個特性類,用來指向table表中不同的字段
??? /// </summary>
??? [AttributeUsage(AttributeTargets.Property)]
??? class FieldAttribute : Attribute
??? {
??????? string fieldname;
??????? public FieldAttribute(string fieldname)
??????? {
??????????? this.fieldname = fieldname;
??????? }//為特性類定義一個定位參數,用來保存唯一且必須存在的值,表示表中的字段名稱
??????? public string FieldName
??????? {
??????????? get
??????????? {
??????????????? return fieldname;
??????????? }
??????? }//為fieldname定義一個屬性,使得它在外部可以被訪問的到 public bool IsPrimaryKey
??????? {
??????????? get;
??????????? set;
??????? }//表示是否為表中的主鍵
??? }
??? interface IEntity
??? {
??? }
??? //第二步:使用特性類
??? [Table("blogs")]
??? class Blog : IEntity
??? {
??????? [Field("ID", IsPrimaryKey = true)]//在Blog這個類里定義了四個字段,對應四個屬性,這四個字段分別是博客編號、博客作者、博客主題、博客的創建時間,分別對這四個屬性使用外部定義好的特性,例如第一個屬性表示博客編號的屬性ID,它引用了外部的特性,映射在blogs表中其存儲為ID(特性定義中的定位參數)同時在特性中定義了IsPrimaryKey=true,表示該字段是blogs表中的主鍵,通俗地說要想使該類的屬性都可以存儲對應blogs表中的字段,必須對該表所有的屬性都套用外部定義好針對屬性的特性FieldAttribute
??????? public int ID
??????? {
??????????? get;
??????????? set;
??????? }
??????? [Field("ZuoZhe")]
??????? public string Author
??????? {
??????????? get;
??????????? set;
??????? }
??????? [Field("BiaoTi")]
??????? public string Title
??????? {
??????????? get;
??????????? set;
??????? }
??????? [Field("ShiJian")]
??????? public DateTime CreateDate
??????? {
??????????? get;
??????????? set;
??????? }
??? }
?? // [Table("articles")]
??? class Article : IEntity
??? {
??????? [Field("ID", IsPrimaryKey = true)]
??????? public int ID
??????? {
??????????? get;
??????????? set;
??????? }//博客編號,主鍵
??????? [Field("TM")]
??????? public string Title
??????? {
??????????? get;
??????????? set;
??????? }//博客主題
??????? [Field("NR")]
??????? public string Content
??????? {
??????????? get;
??????????? set;
??????? }//博客內容
??????? [Field("LX")]
??????? public string Type
??????? {
??????????? get;
??????????? set;
??????? }//博客類型 public int T
??????? {
??????????? get;
??????????? set;
??????? }//這個屬性沒有附加特性 }
}
3、序列化:將對象狀態轉換為可保持(保存)或傳輸的形式的過程。序列化的補集是反序列化,后者將流轉換為對象,這兩個過程一起保證數據易于存儲和傳輸,本質是存儲字段(數據),中間的方法等其他的都不去序列化。 序列化的兩種方式:
?????? 1)序列化二進制(占用空間小)
?????? 2)序列化XML(格式很好,但文件較大) 序列化的命名空間
?????????? 1)二進制序列化需要的命名空間
????????????? using System.Runtime.Serialization;
????????????? using System.Runtime.Serialization.Formatters.Binary; 2)XML序列化需要的命名空間
????????????? using System.Runtime.Serialization.Formatters.Soap;(需要添加引用) 選擇序列化:
??? [Serializable]//加了這個標志后表示該成員可以被序列化
??? public class Person
??? {????????
?????? [NonSerialized]
??????? public? int age;//這個age將不會序列化
??????? public bool Sex
??????? {? get;? set;? }
??? } 序列化的小練習:??
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Collections ;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters .Binary ;
using System.Runtime.Serialization.Formatters.Soap; namespace Client
{
??? class Program
??? { static void Main(string[] args)
??????? {
??????????? Person xihong = new Person();
??????????? xihong.Name = "小紅";
??????????? xihong.Age = "21"; 序列化為二進制文件
??????????? //IFormatter formatter = new BinaryFormatter();//格式化器
??????????? //Stream stream = new FileStream ("D:/a.bin",FileMode.Create ,FileAccess.Write );
??????????? //formatter.Serialize(stream,xihong );
??????????? //stream.Close(); 序列化為XML文件
??????????? //IFormatter formatter1 = new SoapFormatter();
??????????? //Stream stream1 = new FileStream("D:/a.xml", FileMode.Create, FileAccess.Write);
??????????? //formatter1.Serialize(stream1, xihong);
??????????? //stream1.Close(); //反序列化
??????????? IFormatter formatter = new BinaryFormatter();
??????????? Stream stream = new FileStream("D:/a.bin",FileMode.Open ,FileAccess.Read );
??????????? Person xi = (Person)formatter.Deserialize(stream);//將二進制文件中的流反序列化出來轉換成XiHong 這個類類型,并保存在一個新的對象xi中,注:這個新對象xi同原來的對象xihong只是數據一樣,本質是不同的
??????????? Console.WriteLine(xi.Name );
??????????? Console.WriteLine(xi.Age ); Console.WriteLine(xi.Equals(xihong));//此時是返回false,因為這個新對象xi同原來的對象xihong只是數據一樣,本質是不同的
??????? }??????
??????
??? }
??? [Serializable ]
??? class Person
??? {
??????? public string Name
??????? {
??????????? get;
??????????? set;
??????? }
??????
??????? public string Age
??????? {
??????????? get;
??????????? set;
??????? }
??? }
?
?
轉載于:https://blog.51cto.com/fayling/626665
總結
以上是生活随笔為你收集整理的.NET Framework- 反射特性序列化(Day4)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ASP.NET 链接 Access 数据
- 下一篇: 解决不是有效的win32应用程序