反射 特性
反射:從exe文件把本身定義的類型和成員查找出來 引用system.reflection
想調用一個實例化的字段須要new一個當前對象去調用
反射的好處:能夠經過配置文件和路徑獲得定義的類中的全部成員也可經過對象類調用全部成員私有的用BindingFlags.NonPublic|BindingFlags.Instance調用
.ctor:構造函數
練習分別調用方法 屬性 字段構造函數(有參 無參) 索引器
反射屬於命名空間的類型和成員才能反射出來命名空間內引用的成員不能反射出來。
反射的使用:
Assembly ass = Assembly.LoadFrom(@"C:\Users\rui\Documents\Visual Studio 2010\Projects\FanShe\ConsoleApplication1\bin\Debug\ConsoleApplication1.exe");//使用Assembly的LoadForm方法加載程序集
object o = ass.CreateInstance("ConsoleApplication1.Program");//從程序集中查找指定的類型 參數命名空間
//調用方法 要反射的對象.GetType().GetMethod("方法名");
Type type = o.GetType();
MethodInfo mi = type.GetMethod("Method");
mi.Invoke(o, null);
//調用字段 要反射的對象.GetType().GetField("字段名");
FieldInfo fi = o.GetType().GetField("str", BindingFlags.NonPublic | BindingFlags.Instance);
Console.WriteLine(fi.GetValue(o));
//調用屬性 要反射的對象.GetType().GetProperty("屬性名");
PropertyInfo pi = o.GetType().GetProperty("Name", BindingFlags.Public | BindingFlags.Instance);
pi.SetValue(o, "屬性", null);//能夠傳一個參數過去
Console.WriteLine(pi.GetValue(o, null));// 要反射的對象.GetType().GetProperty("屬性名").GetValue(要反射的對象,null); 得到字段的屬性
//調用一個無參的構造函數 要反射的對象.GetType().GetConstructor(new Type[0]);
ConstructorInfo ci = o.GetType().GetConstructor(new Type[0]);
object Obj = ci.Invoke(null);
//調用有參的構造函數
Type[] type2 = new Type[] { typeof(string) };//傳入參數類型
object[] oo = new object[] { "hello" };//接受對象類型
ConstructorInfo ci1 = o.GetType().GetConstructor(type2);
ci1.Invoke(oo);
特性Attribute:類中的附屬信息 特性與程序實體關聯後便可在運行時使用名爲反射的技術查詢屬性
特性已兩種形式出現:
一種是在公共語言運行庫 (CLR) 中定義的屬性。
另外一種是能夠建立的用於向代碼中添加附加信息的自定義屬性。此信息可在之後以編程方式檢索。
特性的特色:
屬性可向程序中添加元數據。元數據是嵌入程序中的信息,如編譯器指令或數據描述。
程序可使用反射檢查本身的元數據。
一般使用屬性與 COM 交互。
自定義特性:
特性類實例化時須要放在括號「[ ]」中,
語法: [attributeClass(定位參數1,… 命名參數1,…)]
自定義特性有兩種類型:
定位參數:至關於實例類的構造函數
定義一個構造函數:
命名參數:至關於實例類的屬性,能夠賦值也能夠不賦
利用特性實現數據庫的增刪改查(這個能夠對數據庫中的數據進行操做)
首先定義特性類來與表想關聯
定義特性的方法以下:
首先聲明一個類來保存數據
[AttributeUsage(AttributeTargets.Class)]//對這個特性進行使用的限制 這裏AttributeTargets後面是Class即這個特性只能加在類型上 特性能夠加在對任何程序元素上 要靠在這裏的限定 如能夠加在字段 ,委託,構造函數,類,屬性,枚舉,事件,接口,方法,模塊等
//還能夠設置命名參數,AllowMultiple等於true表示能夠爲程序集設計多個特性 false是除了目前設定的不能再爲程序集設計別的特性了
//還能夠加Inherited表示該特性是否容許派生類繼承或者容許重載
//定義類型的特性
class TableAttrribute : Attribute//這個特性類必定要繼承Attritube
{
//聲明一個定位參數,即構造函數
string tablename;
public TableAttrribute(string tablename)
{
this.tablename = tablename;
}
//聲明一個對外公佈的屬性
public string TableName
{
get
{
return tablename;
}
}
}
//定義屬性的特性
//定義特性屬性來與表中的字段相關聯
[AttributeUsage(AttributeTargets.Property)]
class FieldAttrribute : Attribute
{
string fieldname;
public FieldAttrribute(string fieldname)
{
this.fieldname = fieldname;
}
public string FieldName
{
get
{
return fieldname;
}
}
public bool IsPrimary//由於這裏用到ID與表映射時要考慮到是不是主鍵
{
get;
set;
}
}
//定義一個Blog類來保存業務邏輯數據,並定義其中的字段
[TableAttrribute("Blog")]//使用特性,這裏的"Blog"至關於表中的字段,與業務邏輯裏的類型相映射
class Blog : IEntify
{
[FieldAttrribute("ID", IsPrimary = true)]
public int ID//咱們在業務邏輯中定義的字段,想要和表關聯起來要對字段也設置特性
{
get;
set;
}
[FieldAttrribute("biaoti")]
public string Title
{
get;
set;
}
[FieldAttrribute("zuozhe")]
public string Author
{
get;
set;
}
[FieldAttrribute("shijian")]
public string CreateTime
{
get;
set;
}
}
//定義一個實體接口 方便多個實體時將增刪改查分別封裝到方法中
interface IEntify
{
}
使用特性分別反射出表名和字段及字段中的數據:
以刪除爲例:
static string Delete(IEntify entiy)
{
//delete語句:delete 表名 where 主鍵名=值
//首先要用反射來把表中的數據反射出來
TableAttrribute ta = entiy.GetType().GetCustomAttributes(true)[0] as TableAttrribute;//獲取blog這個對象的全部類型的中的自定義特性,而後把它轉換成咱們接下來要使用的TableAttribute類型
string tablename = ta.TableName;//把特性中的TableName屬性賦給一個局部變量tablename 來對應sql語句中的中的表名。
//而後找主鍵名和值
string filename = "";
string filevalue = "";
foreach (PropertyInfo pi in entiy.GetType().GetProperties())//遍歷blog全部的屬性來反射數據庫的特性
{
FieldAttrribute fa = pi.GetCustomAttributes(true)[0] as FieldAttrribute;//獲取屬性中的全部特性並把它轉換爲要使用的FieldAttrribute特性
if (fa.IsPrimary)//判斷是否爲主鍵
{
filename = fa.FieldName; //把特性中的FieldName屬性賦給局部變量filename
filevalue = pi.GetValue(entiy, null).ToString();//把特性中的屬性值賦給局部變量filevalue
}
}
string sql = "delete " + tablename + " where " + filename + " = " + filevalue;//組裝sql語句
return sql;
}
更新:
static string Update(IEntify entiy)
{
//update語句:update 表名 set 字段1=值1,字段2=值2,字段3=值3 where 主鍵名=值
//反射出表名
TableAttrribute ta = entiy.GetType().GetCustomAttributes(true)[0] as TableAttrribute;
string tablename = ta.TableName;
//反射表中的字段數據
//巧妙之處;用一個 HashTable來存儲,哈希表的鍵對應字段 哈希表的值 對應值
Dictionary<string, string> pro = new Dictionary<string, string>();
string filename = "";
string filevalue = "";
foreach (PropertyInfo pi in entiy.GetType().GetProperties())
{
FieldAttrribute fa = pi.GetType().GetCustomAttributes(true)[0] as FieldAttrribute;
if (fa.IsPrimary)//找出主鍵
{
filename = fa.FieldName;
filevalue = pi.GetValue(entiy, null).ToString();
}
else//把不是主鍵的字段放到哈希表裏面
{
pro.Add(fa.FieldName, pi.GetValue(entiy, null).ToString());
}
}
//構造Update語句
string sqlup = "update " + tablename + " set ";
//set的不是一個字段和值 想到了把字段1=值1,字段2=值2,字段3=值3字符串疊加後再傳到總的SQL語句中
foreach (string key in pro.Keys)
{
sqlup += key + "=" + pro[key] + ",";
}
sqlup += sqlup.TrimEnd(',') + " where " + filename + "=" + filevalue;
return sqlup;
}