推薦:對asp.net緩存 的深入了解本篇文章,小編將為大家介紹,對asp.net緩存的深入了解。有需要的朋友可以參考一下
概述反射
• 通過反射可以提供類型信息,從而使得我們開發人員在運行時能夠利用這些信息構造和使用對象。
• 反射機制允許程序在執行過程中動態地添加各種功能。
運行時類型標識
•運行時類型標識(RTTI),可以在程序執行期間判定對象類型。例如使用它能夠確切地知道基類引用指向了什么類型對象。
•運行時類型標識,能預先測試某個強制類型轉換操作,能否成功,從而避免無效的強制類型轉換異常。
•在c#中有三個支持RTTI的關鍵字:is 、 as 、typeof。 下面依次介紹他們
is運算符:
通過is運算符,能夠判斷對象類型是否為特頂類型,如果兩種類型是相同類型,或者兩者之間存在引用,裝箱拆箱轉換,則表明兩種類型是兼容的。
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
if (a is A)
{
Console.WriteLine("a is an A"); //這個打印,因為a 是 A 類型的對象
}
if (b is A)
{
//這個打印,因為b是B類型的對象,而B類型派生于A類型,由于b對象可以轉換為A類型,因此b對象與A類型是兼容的,但是反過來就不成立,例如下面不打印
Console.WriteLine("b is an A because it is derived from");
}
if (a is B)
{
//這個不打印
Console.WriteLine("This won't display , because a not derived from B");
}
if (a is object)
{
//這個打印
Console.WriteLine("a is an object");
}
Console.ReadKey();
}
}
class A { }
class B : A { }
class Program
{
static void Main(string[] args)
{
A a = new A();
B b = new B();
if (a is B)
{
b = (B)a; //由于a變量不是B類型,因此這里將a變量轉換為B類型是無效的。
}
else
{
b = null;
}
if (b ==null)
{
//這個打印
Console.WriteLine("The cast in b=(B)a is not allowed");
}
//上面使用as運算符,能夠把兩部合二為一。
b = a as B; //as類型先檢查強制類型轉換的有效性,如果有效,則執行強類型轉換過程。這些都在這一句完成。
if (b == null)
{
//這個打印
Console.WriteLine("The cast in b=(B)a is not allowed");
}
Console.ReadKey();
}
}
class A { }
class B : A { }
static void Main(string[] args)
{
Type t=typeof(StringBuilder);
Console.WriteLine(t.FullName); //FullName屬性返回類型的全稱
if (t.IsClass)
{
Console.WriteLine("is a class"); //打印
}
if (t.IsSealed) //是否為密封類
{
Console.WriteLine("is Sealed"); //打印
}
Console.ReadKey();
}
請注意
•MemberType屬性的返回類型為MemberTypes,這是一個枚舉,它定義了用于表示不同成員的類型值。這些值包括:MemberTypes.Constructor, MemberTypes.Method, MemberTypes.Field, MemberTypes.Event, MemberTypes.Property。因此可以通過檢查MemberType屬性來確定成員的類型,例如,在MemberType屬性的值為MemberTypes.Method時,該成員為方法
•MemberInfo類還包含兩個與特性相關的抽象方法:
1.GetCustomAttributes() :獲得與主調對象關聯的自定義特性列表。
2.IsDefined(): 確定是否為主調對象定義了相應的特性。
3.GetCustomAttributesData():返回有關自定義特性的信息(特性稍后便會提到)
當然除了MemberInfo類定義的方法和屬性外,Type類自己也添加了許多屬性和方法:如下表(只列出一些常用的,太多了,自己可以轉定義Type類看下)
下面列出Type類定義的常用的只讀屬性
使用反射
上面的列術都是為了,這里的使用。
通過使用Type類定義的方法和屬性,我們能夠在運行時獲得類型的各種具體信息。這是一個非常強大的功能。我們一旦得到類型信息,就可以調用其構造函數,方法,和屬性。可見,反射是允許使用編譯時不可用的代碼的。
由于Reflection API非常多,這里不可能完整的介紹他們(這里如果完整的介紹,據說要一本書,厚書)。但是,Reflection API是按照一定邏輯設計的。因此,只要知道部分接口的使用方法,就可以舉一反三的使用剩余的接口。
這里我列出四種關鍵的反射技術:
1.獲取方法的信息
2.調用方法
3.構造對象
4.從程序集中加載類型
獲取方法的相關信息
一旦有了Type對象就可以使用GetMethodInfo()方法獲取此類型支持的方法列表。該方法返回一個MethodInfo 對象數組,MethodInfo對象描述了主調類型所支持的方法,他位于System.Reflection命名空間中
MethodInfo類派生于MethodBase抽象類,而MethodBase類繼承了MemberInfo類。因此我們能夠使用這三個類定義的屬性和方法。例如,使用Name屬性得到方法名稱。這里有兩個重要的成員:
1. ReturnType屬性 :為Type類型的對象,能夠提供方法的返回類型信息
2. GetParameters()方法 :返回參數列表,參數信息以數組形式保存在PatameterInfo對象中。PatameterInfo類定義了大量描述參數信息的屬性和方法。這里也列出兩個常用的屬性 :Name(包含參數名稱信息的字符串),ParameterType(參數類型的信息)。
下面代碼,我將使用反射獲得類中所支持的方法,還有方法的信息。
class MyClass
{
int x;
int y;
public MyClass(int i, int j)
{
x = i;
y = j;
}
public int sum()
{
return x + y;
}
public bool IsBetween(int i)
{
if (x < i && i < y) return true;
else return false;
}
public void Set(int a, int b)
{
x = a;
y = b;
}
public void Set(double a, double b)
{
x = (int)a;
y = (int)b;
}
public void Show()
{
Console.WriteLine("x:{0},y:{1}",x,y);
}
}
class ReflectDemo
{
static void Main(string[] args)
{
Type t=typeof(MyClass); //獲取描述MyClass類型的Type對象
Console.WriteLine("Analyzing methods in "+t.Name); //t.Name="MyClass"
MethodInfo[] mi = t.GetMethods(); //MethodInfo對象在System.Reflection命名空間下。
foreach (MethodInfo m in mi) //遍歷mi對象數組
{
Console.Write(m.ReturnType.Name); //返回方法的返回類型
Console.Write(" " + m.Name + "("); //返回方法的名稱
ParameterInfo[] pi = m.GetParameters(); //獲取方法參數列表并保存在ParameterInfo對象數組中
for (int i = 0; i < pi.Length; i++)
{
Console.Write(pi[i].ParameterType.Name); //方法的參數類型名稱
Console.Write(" "+pi[i].Name); // 方法的參數名
if (i + 1 < pi.Length)
{
Console.Write(", ");
}
}
Console.Write(")");
Console.WriteLine(); //換行
}
Console.ReadKey();
}
}
bool Equals(object obj) int GetHashCode() Type GetType() string ToString()
注意:這里輸出的除了MyClass類定義的所有方法外,也會顯示object類定義的共有非靜態方法。這是因為c#中的所有類型都繼承于object類。另外,這些信息實在程序運行時動態獲得的,并不需要預先知道MyClass類的定義
GetMethods()方法的另一種形式
這種形式可以制定各種標記,已篩選想要獲取的方法。他的通用形式為:MethodInfo[] GetMethods(BindingFlags bindingAttr)
BindingFlags是一個枚舉,枚舉值有(很多只列出5個吧):
1.DeclareOnly:僅獲取指定類定義的方法,而不獲取所繼承的方法;
2.Instance:獲取實例方法
3.NonPublic: 獲取非公有方法
4.Public: 獲取共有方法
5.Static:獲取靜態方法
GetMethods(BindingFlags bindingAttr)這個方法,參數可以使用or把兩個或更多標記連接在一起,實際上至少要有Instance(或Static)與Public(或NonPublic)標記。否則將不會獲取任何方法。
class MyClass
{
int x;
int y;
public MyClass(int i, int j)
{
x = i;
y = j;
}
private int sum()
{
return x + y;
}
public bool IsBetween(int i)
{
if (x < i && i < y) return true;
else return false;
}
public void Set(int a, int b)
{
x = a;
y = b;
}
public void Set(double a, double b)
{
x = (int)a;
y = (int)b;
}
public void Show()
{
Console.WriteLine("x:{0},y:{1}",x,y);
}
}
class ReflectDemo
{
static void Main(string[] args)
{
Type t=typeof(MyClass); //獲取描述MyClass類型的Type對象
Console.WriteLine("Analyzing methods in "+t.Name); //t.Name="MyClass"
MethodInfo[] mi = t.GetMethods(BindingFlags.DeclaredOnly|BindingFlags.Instance|BindingFlags.Public); //不獲取繼承方法,為實例方法,為公開的
foreach (MethodInfo m in mi) //遍歷mi對象數組
{
Console.Write(m.ReturnType.Name); //返回方法的返回類型
Console.Write(" " + m.Name + "("); //返回方法的名稱
ParameterInfo[] pi = m.GetParameters(); //獲取方法參數列表并保存在ParameterInfo對象數組中
for (int i = 0; i < pi.Length; i++)
{
Console.Write(pi[i].ParameterType.Name); //方法的參數類型名稱
Console.Write(" "+pi[i].Name); // 方法的參數名
if (i + 1 < pi.Length)
{
Console.Write(", ");
}
}
Console.Write(")");
Console.WriteLine(); //換行
}
Console.ReadKey();
}
}
使用反射調用方法
上面我們通過反射獲取到了類中的所有信息,下面我們就再使用反射調用通過反射獲取到的方法。
要調用反射獲取到的方法,則需要在MethodInfo實例上調用Invoke() 方法。Invoke()的使用,在下面例子中演示,說明。
下面例子是:先通過反射獲取到要調用的方法,然后使用Invoke()方法,調用獲取到的指定方法;
class MyClass
{
int x;
int y;
public MyClass(int i, int j)
{
x = i;
y = j;
}
private int sum()
{
return x + y;
}
public bool IsBetween(int i)
{
if (x < i && i < y) return true;
else return false;
}
public void Set(int a, int b)
{
Console.Write("Inside set(int,int).");
x = a;
y = b;
Show();
}
public void Set(double a, double b)
{
Console.Write("Inside set(double,double).");
x = (int)a;
y = (int)b;
Show();
}
public void Show()
{
Console.WriteLine("x:{0},y:{1}", x, y);
}
}
class InvokeMethDemo
{
static void Main()
{
Type t=typeof(MyClass);
MyClass reflectOb = new MyClass(10, 20);
reflectOb.Show(); //輸出為: x:10, y:20
MethodInfo[] mi = t.GetMethods();
foreach (MethodInfo m in mi)
{
ParameterInfo[] pi = m.GetParameters();
if (m.Name.Equals("Set", StringComparison.Ordinal) && pi[0].ParameterType == typeof(int))
{
object[] args = new object[2];
args[0] = 9;
args[1] = 10;
//參數reflectOb,為一個對象引用,將調用他所指向的對象上的方法,如果為靜態方法這個參數必須設置為null
//參數args,為調用方法的參數數組,如果不需要參數為null
m.Invoke(reflectOb, args); //調用MyClass類中的參數類型為int的Set方法,輸出為Inside set(int,int).x:9, y:10
}
}
Console.ReadKey();
}
}
class MyClass
{
int x;
int y;
public MyClass(int i)
{
x = y + i;
}
public MyClass(int i, int j)
{
x = i;
y = j;
}
public int sum()
{
return x + y;
}
}
class InvokeConsDemo
{
static void Main()
{
Type t = typeof(MyClass);
int val;
ConstructorInfo[] ci = t.GetConstructors(); //使用這個方法獲取構造函數列表
int x;
for (x = 0; x < ci.Length; x++)
{
ParameterInfo[] pi = ci[x].GetParameters(); //獲取當前構造函數的參數列表
if (pi.Length == 2) break; //如果當前構造函數有2個參數,則跳出循環
}
if (x == ci.Length)
{
return;
}
object[] consargs = new object[2];
consargs[0] = 10;
consargs[1] = 20;
object reflectOb = ci[x].Invoke(consargs); //實例化一個這個構造函數有兩個參數的類型對象,如果參數為空,則為null
//實例化后,調用MyClass中的方法
MethodInfo[] mi = t.GetMethods(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance);
foreach (MethodInfo m in mi)
{
if (m.Name.Equals("sum", StringComparison.Ordinal))
{
val = (int)m.Invoke(reflectOb, null); //由于實例化類型對象的時候是用的兩個參數的構造函數,所以這里返回的結構為30
Console.WriteLine(" sum is " + val); //輸出 sum is 30
}
}
Console.ReadKey();
}
}
借助Reflection API,可以加載程序集,獲取它的相關信息并創建其公共可用類型的實例。通過這種機制,程序能夠搜索其環境,利用潛在功能,而無需在編譯期間顯式的定義他們。這是一個非常有效,且令人興奮的概念。
為了說明如何獲取程序集中的類型,我創建兩個文件。第一個文件定義一組類,第二個文件則反射各個類的信息。 代碼效果如下。
1.這下面代碼是要編譯生成MyClass.exe文件的
class MyClass
{
int x;
int y;
public MyClass(int i)
{
x = y + i;
}
public MyClass(int i, int j)
{
x = i;
y = j;
}
public int sum()
{
return x + y;
}
}
class Demo
{
static void Main()
{
Console.WriteLine("hello word !");
Console.ReadKey();
}
}
class Class3
{
static void Main() {
Assembly asm = Assembly.LoadFrom(@"C:/Users/lenovo/Documents/visual studio 2010/Projects/Reflection_test/ConsoleApplication1/bin/Debug/MyClass.exe"); //加載指定的程序集
Type[] alltype = asm.GetTypes(); //獲取程序集中的所有類型列表
foreach (Type temp in alltype)
{
Console.WriteLine(temp.Name); //打印出MyClass程序集中的所有類型名稱 MyClass , Demo
}
Console.ReadKey();
}
}
分享:IsPostBack原理的介紹本篇文章,小編將為大家介紹,關于IsPostBack的原理,有需要的朋友可以參考一下
新聞熱點
疑難解答
圖片精選