最近項目上使用到到反射,找到以前保留的一份文檔,作者是李志偉,沒有找到他的博客地址,所以不知道出處在哪,抱歉!如果作者看到,請聯系我好注明出處。
在這分享一下。
審查元數據並收集關於它的類型信息的能力稱為反射。元數據(編譯以後的最基本數據單元)就是一大堆的表,當編譯程序集或者模塊時,編譯器會創建一個類定義表,一個字段定義表,和一個方法定義表等。System.reflection命名空間包含的幾個類,允許用戶解析這些元數據表的代碼:
System.Reflection.Assembly:表示一個程序集。
System.Reflection.Module:在模塊上執行反射。
System.Type:表示各種類型。
System.Reflection.MethodBase:提供有關方法和構造函數的信息。
System.Reflection.MethodInfo:發現方法的屬性並提供對方法元數據的訪問。
System.Reflection.MemberInfo:獲取或訪問有關成員屬性。
System.Reflection.FieldInfo:發現字段屬性並提供對字段元數據的訪問權。
System.Reflection.PropertyInfo:發現或訪問屬性(Property)的屬性(Attribute)。
System.Reflection.EventInfo:發現事件的屬性並提供對事件元數據的訪問權。
System.Reflection.ConstructorInfo:發現或訪問類構造函數的屬性。
class Program
{
static void Main(string[] args)
{
Assembly assem = Assembly.Load("mscorlib");//加載系統程序集
PrintInfo(assem);//輸出程序集相關信息
assem = Assembly.LoadFrom(@"F:\System.Data.SQLite.dll");//或使用LoadFile()方法
PrintInfo(assem);//輸出程序集相關信息
assem = Assembly.GetExecutingAssembly();//獲取當前執行代碼的程序集
PrintInfo(assem);//輸出程序集相關信息
Console.Read();
}
//輸出程序集相關信息
static void PrintInfo(Assembly assem)
{
Console.WriteLine("程序集全名:" + assem.FullName);
Console.WriteLine("程序集的版本:" + assem.GetName().Version);
Console.WriteLine("程序集初始位置:" + assem.CodeBase);
Console.WriteLine("程序集位置:" + assem.Location);
Console.WriteLine("程序集入口:" + assem.EntryPoint);
Type[] types = assem.GetTypes();//得到該程序集裡所有的類型
Console.WriteLine("程序集下包含的類型數:" + types.Length);
//foreach (var item in types)
//{
// Console.WriteLine("類:" + item.Name);//輸出類型名
//}
Console.WriteLine("============================\n");
}
}
class Program
{
static void Main(string[] args)
{
Assembly assembly = Assembly.Load("mscorlib");//加載程序集
Module module = assembly.GetModule("CommonLanguageRuntimeLibrary");//得到指定模塊
Console.WriteLine("模塊名:"+module.Name);
Type[] types = module.FindTypes(Module.FilterTypeName, "Assembly*");
foreach (var item in types)
{
Console.WriteLine("類名:" + item.Name);//輸出類型名
}
Console.Read();
}
}
class Myclass
{
private int Id;
public string Name;
public void Method(int i) { }
}
class Program
{
static void Main(string[] args)
{
Type type = typeof(Myclass);
Console.WriteLine("類型名:" + type.Name);
Console.WriteLine("類全名:" + type.FullName);
Console.WriteLine("命名空間名:" + type.Namespace);
Console.WriteLine("程序集名:" + type.Assembly);
Console.WriteLine("模塊名:" + type.Module);
Console.WriteLine("基類名:" + type.BaseType);
Console.WriteLine("是否類:" + type.IsClass);
Console.WriteLine("類的公共成員:");
MemberInfo[] memberInfos = type.GetMembers();//得到所有公共成員
foreach (var item in memberInfos)
{
Console.WriteLine("成員類型:" + item.MemberType + "\t成員:" + item);
}
Console.Read();
}
}
class Myclass
{
public Myclass()
{
Console.WriteLine("創建Myclass對象!");
}
public void Method(int i)
{
Console.WriteLine("輸出值:" + i);
}
}
class Program
{
static void Main(string[] args)
{
Type t = typeof(Myclass);//得到類型
object o = Activator.CreateInstance(t);//創建類型的實例
Console.WriteLine("已創建Myclass對象:" + o);
MethodInfo method = t.GetMethod("Method");//獲得實例的方法
method.Invoke(o, new object[] { 100 });//調用方法
Console.Read();
}
}
Attributes是一種新的描述信息,我們既可以使用attributes來定義設計信息(例如:幫助文件,文檔的URL),還可以用attributes定義運行時信息(例如,使XML中的元素與類的成員字段關聯起來)。我們也可以用attributes來創建一個“自描述”的組件。
class Program
{
[Obsolete("已過時的方法!", true)]//把true改成false就可以編譯通過
static void OldMethod() { }
static void Main(string[] args)
{
OldMethod();//調用過時的方法
Console.Read();
}
}
在該實例中我們用到了“Obsolete”Attribute,它標記了一個不該再被使用的語言元素(這裡的元素為方法),該屬性的第一個參數是string類型,它解釋為什麼該元素被荒棄,以及我們該使用什麼元素來代替它。實際中,我們可以書寫任何其它文本來代替這段文本。第二個參數是告訴編譯器把依然使用這被標識的元素視為一種錯誤,這就意味著編譯器會因此而產生一個警告。
自定義的Attribute類都派生於System.Attribute類。
//自定義的Attribute類命名為XXXAttribute
class HelpAttribute : Attribute
{
private String description;
public HelpAttribute(String Descrition_in)
{
this.description = Descrition_in;
}
public String Description
{
get { return description; }
}
}
class Program
{
[Help("自定義特性")]//使用是不需要寫“Attribute”後綴
static void Main(string[] args)
{
Console.Read();
}
}
注意:按慣例我們是用”Attribute“作為attribute類名的後綴,然而,當我們當我們把attribute綁定到某語言元素時,是不包含“Attribute“後綴的。編譯器首先在System.Attribute 的繼承類中查找該attribute,如果沒有找到,編譯器會把“Attribute“追加到該attribute的名字後面,然後查找它。
AttributeUsage類是另一預定義類(Attribute類本身用System.AttributeUsage類來標記),它將幫助我們控制我們自定義Attribute類的用法,這就是,我們能為自定義的Attribute類定義Attributes屬性。它描述了一個自定義Attribute類能被怎樣使用。
AttributeUsage提供三個屬性,我們能將它們放置到我們的自定義Attribute類上。
AllowMultiple屬性:該值指示能否為一個程序元素指定多個指示屬性實例。
Inherited屬性:該值指示指示的屬性能否由派生類和重寫成員繼承。
ValidOn屬性:獲取一組值,這組值標識指示的屬性可應用到的程序元素。此屬性是AttributeTargets類型的枚舉,可取如下值:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
class HelpAttribute : Attribute
{
private String description;
public HelpAttribute(String Descrition_in)
{
this.description = Descrition_in;
}
public String Description
{
get { return description; }
}
}
class Program
{
[Help("自定義特性")]
static void Main(string[] args)
{
Console.Read();
}
}
可選參數是Attribute類構造函數的參數。它是強制的,必須在每次在Attribute綁定至某語言元素時提供一個值。而另一方面,命名參數倒是真正的可選參數,不是在Attribute構造函數的參數。
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
class HelpAttribute : Attribute
{
private string _description;//可選參數
public string _name;//命名參數
public HelpAttribute(string description)
{
Console.WriteLine("HelpAttribute特性被創建!");
this._description = description;
}
public string Description
{
get { return _description; }
}
public string Name
{
get { return _name; }
set//命名參數,必須要有set方法
{
Console.WriteLine("屬性:" + value);
_name = value;
}
}
}
class Program
{
[Help("自定義特性", Name = "李志偉")]//同時使用可選參數與命名參數
static void Main(string[] args)
{
Console.Read();
}
}
假設,我們想把HelpAttribute綁定到整個assembly(程序集)。第一個問題是我們要把HelpAttribute放在哪兒才能讓編譯器確定該Attribute是綁定至整個assembly呢?考慮另一種情況,我們想把Attribute綁定至一個方法的返回類型上,怎樣才能讓編譯器確定我們是把Attribute綁定至方法的返回類型上,而不是整個方法呢?
為了解決諸如此類的含糊問題,我們使用Attribute標識符,有了它的幫助,我們就可以確切地申明我們把attribute 綁定至哪一個語言元素。例如:[assembly: Help("類上的自定義特性", Name = "lizhiwei")]這個在HelpAttribute前的assembly標識符確切地告訴編譯器,該Attribute被綁定至整個assembly(程序集)。可能的標識符有:assembly、module、type、method、property、event、field、param、return。
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
class HelpAttribute : Attribute
{
private string _description;//可選參數
private string _name;//命名參數
public HelpAttribute(string description)
{
Console.WriteLine("====HelpAttribute特性被創建!====");
this._description = description;
}
public string Description
{
get { return _description; }
}
public string Name
{
get { return _name; }
set//命名參數,必須要有set方法
{
Console.WriteLine("====屬性:" + value + "====");
_name = value;
}
}
}
//使用了自定義特性的測試類
[Help("類上的自定義特性", Name = "lizhiwei")]
class TestClass
{
[Help("方法上的自定義特性", Name = "李志偉1")]
[Help("方法上的自定義特性", Name = "李志偉2")]
public void TestMethod()
{
Console.WriteLine("===========測試方法===========");
}
}
class Program
{
static void Main(string[] args)
{
Type t = typeof(TestClass);
//獲取類上的自定義特性
object[] obis = t.GetCustomAttributes(typeof(HelpAttribute), false);
HelpAttribute attribute = obis[0] as HelpAttribute;
Console.WriteLine("\n" + attribute.Description + "--" + attribute.Name + "\n");
//獲取方法上的自定義特性
MethodInfo method = t.GetMethod("TestMethod");
object[] methods = method.GetCustomAttributes(typeof(HelpAttribute), false);
foreach (HelpAttribute help in methods)
{
Console.WriteLine("\n" + help.Description + "--" + help.Name + "\n");
}
Console.Read();
}
}