小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C#之玩轉(zhuǎn)反射

 圖書(shū)館煮飯少年 2018-01-03

前言

之所以要寫(xiě)這篇關(guān)于C#反射的隨筆,起因有兩個(gè):

  第一個(gè)是自己開(kāi)發(fā)的網(wǎng)站需要用到

  其次就是沒(méi)看到這方面比較好的文章。

所以下定決心自己寫(xiě)一篇,廢話不多說(shuō)開(kāi)始進(jìn)入正題。

 

前期準(zhǔn)備

VS2012中新建一個(gè)控制臺(tái)應(yīng)用程序(我的命名是ReflectionStudy),這個(gè)項(xiàng)目是基于.net 4.0。接著我們打開(kāi)Program.cs文件,按照如下在Program中寫(xiě)一個(gè)我們自己的類(lèi):

復(fù)制代碼
 1         public class RefClass
 2         {
 3             private int _test3;
 4             private int _test1 { get; set; }
 5             protected int Test2 { get; set; }
 6             public int Test3 { get; set; }
 7 
 8             public void Show()
 9             {
10 
11             }
12         }
復(fù)制代碼

 

窺視內(nèi)部

常言道知彼知己百戰(zhàn)不殆,所以我們第一步也是關(guān)鍵的一步就是要窺視RefClass類(lèi)的結(jié)構(gòu)(這里我們假設(shè)對(duì)RefClass并不理解)。

首先我們先要縱覽全局才能繼續(xù)深入,所以我們先在Main中寫(xiě)入如下代碼:

復(fù)制代碼
 1         static void Main(string[] args)
 2         {
 3             Type t = typeof(RefClass);
 4             MemberInfo[] minfos = t.GetMembers();
 5             foreach (MemberInfo minfo in minfos)
 6             {
 7                 Console.WriteLine(minfo.Name);
 8             }
 9             Console.ReadKey();
10         }
復(fù)制代碼

 在這里我們獲取這個(gè)類(lèi)的類(lèi)型,然后獲取了其中的公共成員(可能很多人都會(huì)認(rèn)為GetMembers是獲取全部,但其實(shí)只是獲取公開(kāi)的所有成員。)然后我們通過(guò)foreach將所有的成員的名稱(chēng)循環(huán)輸出。

 

然后我們可以查看控制臺(tái)的輸出:

 

在這里我們可以看到其中不僅僅輸出了我們所寫(xiě)類(lèi)中的成員,同時(shí)還輸出了父類(lèi)的成員(如果不理解的這里幫你們補(bǔ)充下基礎(chǔ),Object是所有類(lèi)的基類(lèi)。),細(xì)心的讀者一定會(huì)發(fā)現(xiàn)這里的輸出并沒(méi)有包含privateprotected訪問(wèn)權(quán)限的成員。這就應(yīng)了上面的那句話:GetMembers默認(rèn)返回公開(kāi)的成員。

 

僅僅只能看到這些公開(kāi)的成員對(duì)我們來(lái)說(shuō)意義并不大,所以我們需要查看到那些非公有的成員。

下面我們將上面的代碼改成如下所示:

復(fù)制代碼
 1         static void Main(string[] args)
 2         {
 3             Type t = typeof(RefClass);
 4             MemberInfo[] minfos = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public );
 5             foreach (MemberInfo minfo in minfos)
 6             {
 7                 Console.WriteLine(minfo.Name);
 8             }
 9             Console.ReadKey();
10         }
復(fù)制代碼

 從中我們看到我們使用了GetMembers重載版本,并且傳入了枚舉類(lèi)型,分別是“包含非公開(kāi)”、“包含實(shí)例成員”和“包含公開(kāi)”。然后我們就可以獲取到所有成員了。

 

最終我們將會(huì)得出下面這些成員:

到這里你可能會(huì)認(rèn)為我們已經(jīng)檢索結(jié)束了,但是你有沒(méi)有發(fā)現(xiàn)屬性很多,而且還包含了大量的父類(lèi)中的屬性,假設(shè)我們只關(guān)注該類(lèi)中的成員,并不關(guān)注父類(lèi)中的成員該如何做呢?

其實(shí)我們只需要加上一個(gè)枚舉類(lèi)型(BindingFlags.DeclaredOnly)

1 MemberInfo[] minfos = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly );

 

然后我們?cè)俨榭唇Y(jié)果:

此時(shí)就只包含該類(lèi)中的成員了。

 

下面我們?cè)?span style="color: #ff0000;">RefClass類(lèi)中添加兩個(gè)靜態(tài)方法,如下所示:

復(fù)制代碼
 1        public class RefClass
 2         {
 3             private int _test3;
 4             private int _test1 { get; set; }
 5             protected int Test2 { get; set; }
 6             public int Test3 { get; set; }
 7 
 8             private static void Show2()
 9             {
10             }
11 
12             public static void Show3()
13             {
14             }
15 
16             public void Show()
17             {
18 
19             }
20         }
復(fù)制代碼

 然后我們繼續(xù)查看,可以發(fā)現(xiàn)最終的結(jié)果并沒(méi)有輸出這些靜態(tài)成員。這個(gè)時(shí)候我們只需要在GetMembers中加上一個(gè)枚舉:BindingFlags.Static即可。

 

這里我們僅僅輸出了所有的成員,但是卻沒(méi)有區(qū)分出是方法還是屬性所以我們?cè)?span style="color: #ff0000;">Main中添加一個(gè)方法:

復(fù)制代碼
 1         static void Main(string[] args)
 2         {
 3             Type t = typeof(RefClass);
 4             Func<MemberTypes, String> getType = (x) =>
 5             {
 6                 switch (x)
 7                 {
 8                     case MemberTypes.Field:
 9                         {
10                             return "字段";
11                         }
12                     case MemberTypes.Method:
13                         {
14                             return "方法";
15                         }
16                     case MemberTypes.Property:
17                         {
18                             return "屬性";
19                         }
20                     default:
21                         {
22                             return "未知";
23                         }
24                 }
25             };
26             MemberInfo[] minfos = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static );
27             foreach (MemberInfo minfo in minfos)
28             {
29                 Console.WriteLine(minfo.Name + ";類(lèi)型:" + getType(minfo.MemberType));
30             }
31             Console.ReadKey();
32         }
復(fù)制代碼

 這里我用了一個(gè)局部方法來(lái)根據(jù)類(lèi)型輸出對(duì)應(yīng)的文本,因?yàn)槠脑蛭揖椭慌袛嗔藥讉€(gè)基本的類(lèi)型。

 

最終輸出的結(jié)果如下:

到此為止我們已經(jīng)能夠窺視整個(gè)結(jié)構(gòu)。

 

深入窺視字段

通過(guò)上面的內(nèi)容我們僅僅縱覽了全局,下面我們將要繼續(xù)深入,首先我們先拿字段下手。

這里我們不在使用GetMembers而需要使用GetFields(當(dāng)然跟GetMembers一樣如果不傳入指定的枚舉只返回公開(kāi)的字段),代碼如下所示:

復(fù)制代碼
 1         static void Main(string[] args)
 2         {
 3             Type t = typeof(RefClass);
 4             FieldInfo[] finfos = t.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
 5             foreach (FieldInfo finfo in finfos)
 6             {
 7                 Console.WriteLine("字段名稱(chēng):{0}  字段類(lèi)型:{1} ", finfo.Name, finfo.FieldType.ToString());
 8             }
 9             Console.ReadKey();
10         }
復(fù)制代碼

 

最終的輸出結(jié)果如下所示:

 

一直到這里大家都會(huì)認(rèn)為我們僅僅只是分析,感覺(jué)沒(méi)有什么實(shí)質(zhì)的東西,下面就來(lái)點(diǎn)實(shí)質(zhì)的東西,你可以看到_test3、_test1Test2私有保護(hù)類(lèi)型,

是不可以獲取到它們的的,但是我們通過(guò)反射卻可以,具體的代碼如下所示:

復(fù)制代碼
 1         static void Main(string[] args)
 2         {
 3             Type t = typeof(RefClass);
 4             RefClass rc = new RefClass();
 5             rc.Test3 = 3;
 6             FieldInfo[] finfos = t.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
 7             foreach (FieldInfo finfo in finfos)
 8             {
 9                 Console.WriteLine("字段名稱(chēng):{0}  字段類(lèi)型:{1} rc中的值為:{2}", finfo.Name, finfo.FieldType.ToString(), finfo.GetValue(rc));
10             }
11             Console.ReadKey();
12         }
復(fù)制代碼

 

可以看到我實(shí)例化了這個(gè)類(lèi),并且設(shè)置了Test33,下面我通過(guò)finfo.GetValue輸出了這個(gè)值,結(jié)果如下圖:

 

現(xiàn)在是不是感覺(jué)有點(diǎn)酷了?這還沒(méi)完呢,我們光獲取不算什么,下面我們還要修改它的

復(fù)制代碼
 1         static void Main(string[] args)
 2         {
 3             Type t = typeof(RefClass);
 4             RefClass rc = new RefClass();
 5             rc.Test3 = 3;
 6             FieldInfo[] finfos = t.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
 7             foreach (FieldInfo finfo in finfos)
 8             {
 9                 finfo.SetValue(rc, 100);
10                 Console.WriteLine("字段名稱(chēng):{0}  字段類(lèi)型:{1} rc中的值為:{2}", finfo.Name, finfo.FieldType.ToString(), finfo.GetValue(rc));
11             }
12             Console.ReadKey();
13         }
復(fù)制代碼

 

這里我只是在foreach中增加了一條語(yǔ)句finfo.SetValue(rc,100),下面我們繼續(xù)看最終輸出的結(jié)果:

是不是現(xiàn)在感覺(jué)可以為所欲為了?但是還沒(méi)有完。

 

深入窺視屬性

因?yàn)閷傩源嬖?strong>getset,并且兩者都是方法,所以比較棘手。我們需要通過(guò)屬性對(duì)象獲取getset方法,在通過(guò)調(diào)用他們才達(dá)到修改這個(gè)屬性的值。

比如下面的代碼:

復(fù)制代碼
 1         static void Main(string[] args)
 2         {
 3             Type t = typeof(RefClass);
 4             RefClass rc = new RefClass();
 5             rc.Test3 = 3;
 6             PropertyInfo[] finfos = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
 7             foreach (PropertyInfo finfo in finfos)
 8             {
 9                 MethodInfo getinfo = finfo.GetGetMethod(true);
10                 Console.WriteLine("get方法的名稱(chēng){0}  返回值類(lèi)型:{1}  參數(shù)數(shù)量:{2}  MSIL代碼長(zhǎng)度:{3} 局部變量數(shù)量:{4}", getinfo.Name, getinfo.ReturnType.ToString(),
11                     getinfo.GetParameters().Count(),
12                     getinfo.GetMethodBody().GetILAsByteArray().Length, 
13                     getinfo.GetMethodBody().LocalVariables.Count);
14 
15                 MethodInfo setinfo = finfo.GetSetMethod(true);
16                 Console.WriteLine("get方法的名稱(chēng){0}  返回值類(lèi)型:{1}  參數(shù)數(shù)量:{2}  MSIL代碼長(zhǎng)度:{3} 局部變量數(shù)量:{4}", setinfo.Name, setinfo.ReturnType.ToString(),
17                     setinfo.GetParameters().Count(),
18                     setinfo.GetMethodBody().GetILAsByteArray().Length,
19                     setinfo.GetMethodBody().LocalVariables.Count);
20 
21                 setinfo.Invoke(rc, new object[] { 123 });
22                 object obj = getinfo.Invoke(rc, null);
23                 Console.WriteLine("方法名:{0}  內(nèi)部值:{1}", finfo.Name, obj);
24             }
25             Console.ReadKey();
26         }
復(fù)制代碼

 

這里我們循環(huán)每個(gè)屬性,通過(guò)GetGetMethod獲取get方法(調(diào)用該方法時(shí)如果傳入true則無(wú)法獲取非公開(kāi)的get方法set也是一樣),接著我們輸出了該方法的返回類(lèi)型參數(shù)數(shù)量MSIL代碼長(zhǎng)度以及局部變量的數(shù)量,

當(dāng)然你如果有興趣可以繼續(xù)分析輸入?yún)?shù)以及局部變量等,這里由于篇幅的緣故就不能介紹太多了。最后我們調(diào)用了set方法將值改變,然后再通過(guò)調(diào)用get方法獲取這個(gè)屬性的值。

 

最終的結(jié)果如下所示:

 

深入窺視方法

首先我們需要將RefClass修改成如下所示:

復(fù)制代碼
 1         public class RefClass
 2         {
 3             private int _test3;
 4             private int _test1 { get; set; }
 5             protected int Test2 { get; set; }
 6             public int Test3 { get; set; }
 7 
 8             private static void Show2()
 9             {
10 
11             }
12 
13             public static string Show3(string s)
14             {
15                 int b;
16                 int c;
17                 return s;
18             }
19 
20             public string Show(string s)
21             {
22                 string a;
23                 return s;
24             }
25         }
復(fù)制代碼

 主要是在方法中增加局部變量并且加上返回值,避免最后輸出的時(shí)候沒(méi)有值。其實(shí)這里的方法跟屬性部分類(lèi)似,但是為了能夠完整的描述所有,所以筆者依然會(huì)講解一遍。

 

下面我們直接上代碼:

復(fù)制代碼
 1         static void Main(string[] args)
 2         {
 3             Type t = typeof(RefClass);
 4             RefClass rc = new RefClass();
 5             rc.Test3 = 3;
 6             MethodInfo[] finfos = t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Static );
 7             foreach (MethodInfo finfo in finfos)
 8             {
 9                 if (finfo.GetParameters().Count() > 0 && finfo.GetParameters()[0].ParameterType == typeof(string) )
10                 {
11                     object obj = finfo.Invoke(rc, new[] { "123" });
12                     MethodBody mbody = finfo.GetMethodBody();
13                     Console.WriteLine("擁有參數(shù)的方法名:{0}  返回值類(lèi)型:{1}  參數(shù)1類(lèi)型:{2}  參數(shù)1名稱(chēng):{3}  方法調(diào)用后返回的值:{4}",
14                         finfo.Name,
15                         finfo.ReturnType.ToString(),
16                         finfo.GetParameters()[0].ParameterType.ToString(),
17                         finfo.GetParameters()[0].Name,
18                         obj.ToString());
19                 }
20                 else
21                 {
22                     MethodBody mbody = finfo.GetMethodBody();
23                     Console.WriteLine("沒(méi)有參數(shù)的方法名:{0}  返回值類(lèi)型:{1}",
24                         finfo.Name,
25                         finfo.ReturnType.ToString());
26                 }
27             }
28             Console.ReadKey();
29         }
復(fù)制代碼

 在這里我進(jìn)行了一些簡(jiǎn)單的判斷比如判斷輸入?yún)?shù)的數(shù)量以及類(lèi)型,如果不進(jìn)行這些判斷就會(huì)導(dǎo)致程序無(wú)法繼續(xù)執(zhí)行,具體為什么可以看下的輸出結(jié)果,你就能明白筆者為什么要這么做了。

 

下面就是具體的結(jié)果:

讀者一定發(fā)現(xiàn)了這其中還有getset,你可能會(huì)認(rèn)為它們不是屬性嗎?怎么跑到方法這里來(lái)了,其實(shí)上面我已經(jīng)說(shuō)了。這些其實(shí)也是方法。這也是為什么上面我需要去判斷輸入?yún)?shù)的數(shù)量以及類(lèi)型的緣故。

 

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多