亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C# > 正文

通俗易懂的C#之反射教程

2020-01-24 02:09:35
字體:
來源:轉載
供稿:網友

前言

之所以要寫這篇關于C#反射的隨筆,起因有兩個:

第一個是自己開發的網站需要用到

其次就是沒看到這方面比較好的文章。

所以下定決心自己寫一篇,廢話不多說開始進入正題。

前期準備

在VS2012中新建一個控制臺應用程序(我的命名是ReflectionStudy),這個項目是基于.net 4.0。接著我們打開Program.cs文件,按照如下在Program中寫一個我們自己的類:

復制代碼 代碼如下:

public class RefClass
        {
            private int _test3;
            private int _test1 { get; set; }
            protected int Test2 { get; set; }
            public int Test3 { get; set; }

            public void Show()
            {

            }
        }

窺視內部

常言道知彼知己百戰不殆,所以我們第一步也是關鍵的一步就是要窺視RefClass類的結構(這里我們假設對RefClass并不理解)。

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

復制代碼 代碼如下:

static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            MemberInfo[] minfos = t.GetMembers();
            foreach (MemberInfo minfo in minfos)
            {
                Console.WriteLine(minfo.Name);
            }
            Console.ReadKey();
        }

在這里我們獲取這個類的類型,然后獲取了其中的公共成員(可能很多人都會認為GetMembers是獲取全部,但其實只是獲取公開的所有成員。)然后我們通過foreach將所有的成員的名稱循環輸出。

然后我們可以查看控制臺的輸出:

在這里我們可以看到其中不僅僅輸出了我們所寫類中的成員,同時還輸出了父類的成員(如果不理解的這里幫你們補充下基礎,Object是所有類的基類。),細心的讀者一定會發現這里的輸出并沒有包含private和protected訪問權限的成員。這就應了上面的那句話:GetMembers默認返回公開的成員。

僅僅只能看到這些公開的成員對我們來說意義并不大,所以我們需要查看到那些非公有的成員。

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

復制代碼 代碼如下:

static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            MemberInfo[] minfos = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public );
            foreach (MemberInfo minfo in minfos)
            {
                Console.WriteLine(minfo.Name);
            }
            Console.ReadKey();
        }

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

 

最終我們將會得出下面這些成員:

到這里你可能會認為我們已經檢索結束了,但是你有沒有發現屬性很多,而且還包含了大量的父類中的屬性,假設我們只關注該類中的成員,并不關注父類中的成員該如何做呢?

其實我們只需要加上一個枚舉類型(BindingFlags.DeclaredOnly):

復制代碼 代碼如下:

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

然后我們再查看結果:

此時就只包含該類中的成員了。

下面我們在RefClass類中添加兩個靜態方法,如下所示:

復制代碼 代碼如下:

public class RefClass
        {
            private int _test3;
            private int _test1 { get; set; }
            protected int Test2 { get; set; }
            public int Test3 { get; set; }

            private static void Show2()
            {
            }

            public static void Show3()
            {
            }

            public void Show()
            {

            }
        }

然后我們繼續查看,可以發現最終的結果并沒有輸出這些靜態成員。這個時候我們只需要在GetMembers中加上一個枚舉:BindingFlags.Static即可。

這里我們僅僅輸出了所有的成員,但是卻沒有區分出是方法還是屬性所以我們在Main中添加一個方法:

復制代碼 代碼如下:

static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            Func<MemberTypes, String> getType = (x) =>
            {
                switch (x)
                {
                    case MemberTypes.Field:
                        {
                            return "字段";
                        }
                    case MemberTypes.Method:
                        {
                            return "方法";
                        }
                    case MemberTypes.Property:
                        {
                            return "屬性";
                        }
                    default:
                        {
                            return "未知";
                        }
                }
            };
            MemberInfo[] minfos = t.GetMembers(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Static );
            foreach (MemberInfo minfo in minfos)
            {
                Console.WriteLine(minfo.Name + ";類型:" + getType(minfo.MemberType));
            }
            Console.ReadKey();
        }

這里我用了一個局部方法來根據類型輸出對應的文本,因為篇幅的原因我就只判斷了幾個基本的類型。

最終輸出的結果如下:

到此為止我們已經能夠窺視整個結構。

深入窺視字段

通過上面的內容我們僅僅縱覽了全局,下面我們將要繼續深入,首先我們先拿字段下手。

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

復制代碼 代碼如下:

static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            FieldInfo[] finfos = t.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            foreach (FieldInfo finfo in finfos)
            {
                Console.WriteLine("字段名稱:{0}  字段類型:{1} ", finfo.Name, finfo.FieldType.ToString());
            }
            Console.ReadKey();
        }

最終的輸出結果如下所示:

一直到這里大家都會認為我們僅僅只是分析,感覺沒有什么實質的東西,下面就來點實質的東西,你可以看到_test3、_test1和Test2是私有和保護類型,

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

復制代碼 代碼如下:

static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            RefClass rc = new RefClass();
            rc.Test3 = 3;
            FieldInfo[] finfos = t.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            foreach (FieldInfo finfo in finfos)
            {
                Console.WriteLine("字段名稱:{0}  字段類型:{1} rc中的值為:{2}", finfo.Name, finfo.FieldType.ToString(), finfo.GetValue(rc));
            }
            Console.ReadKey();
        }

可以看到我實例化了這個類,并且設置了Test3為3,下面我通過finfo.GetValue輸出了這個值,結果如下圖:

現在是不是感覺有點酷了?這還沒完呢,我們光獲取不算什么,下面我們還要修改它的值:

復制代碼 代碼如下:

static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            RefClass rc = new RefClass();
            rc.Test3 = 3;
            FieldInfo[] finfos = t.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            foreach (FieldInfo finfo in finfos)
            {
                finfo.SetValue(rc, 100);
                Console.WriteLine("字段名稱:{0}  字段類型:{1} rc中的值為:{2}", finfo.Name, finfo.FieldType.ToString(), finfo.GetValue(rc));
            }
            Console.ReadKey();
        }

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

是不是現在感覺可以為所欲為了?但是還沒有完。

深入窺視屬性

因為屬性存在get和set,并且兩者都是方法,所以比較棘手。我們需要通過屬性對象獲取get和set方法,在通過調用他們才達到修改這個屬性的值。

比如下面的代碼:

復制代碼 代碼如下:

static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            RefClass rc = new RefClass();
            rc.Test3 = 3;
            PropertyInfo[] finfos = t.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
            foreach (PropertyInfo finfo in finfos)
            {
                MethodInfo getinfo = finfo.GetGetMethod(true);
                Console.WriteLine("get方法的名稱{0}  返回值類型:{1}  參數數量:{2}  MSIL代碼長度:{3} 局部變量數量:{4}", getinfo.Name, getinfo.ReturnType.ToString(),
                    getinfo.GetParameters().Count(),
                    getinfo.GetMethodBody().GetILAsByteArray().Length,
                    getinfo.GetMethodBody().LocalVariables.Count);

                MethodInfo setinfo = finfo.GetSetMethod(true);
                Console.WriteLine("get方法的名稱{0}  返回值類型:{1}  參數數量:{2}  MSIL代碼長度:{3} 局部變量數量:{4}", setinfo.Name, setinfo.ReturnType.ToString(),
                    setinfo.GetParameters().Count(),
                    setinfo.GetMethodBody().GetILAsByteArray().Length,
                    setinfo.GetMethodBody().LocalVariables.Count);

                setinfo.Invoke(rc, new object[] { 123 });
                object obj = getinfo.Invoke(rc, null);
                Console.WriteLine("方法名:{0}  內部值:{1}", finfo.Name, obj);
            }
            Console.ReadKey();
        }

這里我們循環每個屬性,通過GetGetMethod獲取get方法(調用該方法時如果傳入true則無法獲取非公開的get方法set也是一樣),接著我們輸出了該方法的返回類型和參數數量和MSIL代碼長度以及局部變量的數量,

當然你如果有興趣可以繼續分析輸入參數以及局部變量等,這里由于篇幅的緣故就不能介紹太多了。最后我們調用了set方法將值改變,然后再通過調用get方法獲取這個屬性的值。

最終的結果如下所示:

深入窺視方法

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

復制代碼 代碼如下:

public class RefClass
        {
            private int _test3;
            private int _test1 { get; set; }
            protected int Test2 { get; set; }
            public int Test3 { get; set; }

            private static void Show2()
            {

            }

            public static string Show3(string s)
            {
                int b;
                int c;
                return s;
            }

            public string Show(string s)
            {
                string a;
                return s;
            }
        }

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

下面我們直接上代碼:

復制代碼 代碼如下:

static void Main(string[] args)
        {
            Type t = typeof(RefClass);
            RefClass rc = new RefClass();
            rc.Test3 = 3;
            MethodInfo[] finfos = t.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Static );
            foreach (MethodInfo finfo in finfos)
            {
                if (finfo.GetParameters().Count() > 0 && finfo.GetParameters()[0].ParameterType == typeof(string) )
                {
                    object obj = finfo.Invoke(rc, new[] { "123" });
                    MethodBody mbody = finfo.GetMethodBody();
                    Console.WriteLine("擁有參數的方法名:{0}  返回值類型:{1}  參數1類型:{2}  參數1名稱:{3}  方法調用后返回的值:{4}",
                        finfo.Name,
                        finfo.ReturnType.ToString(),
                        finfo.GetParameters()[0].ParameterType.ToString(),
                        finfo.GetParameters()[0].Name,
                        obj.ToString());
                }
                else
                {
                    MethodBody mbody = finfo.GetMethodBody();
                    Console.WriteLine("沒有參數的方法名:{0}  返回值類型:{1}",
                        finfo.Name,
                        finfo.ReturnType.ToString());
                }
            }
            Console.ReadKey();
        }

在這里我進行了一些簡單的判斷比如判斷輸入參數的數量以及類型,如果不進行這些判斷就會導致程序無法繼續執行,具體為什么可以看下的輸出結果,你就能明白筆者為什么要這么做了。

下面就是具體的結果:

讀者一定發現了這其中還有get和set,你可能會認為它們不是屬性嗎?怎么跑到方法這里來了,其實上面我已經說了。這些其實也是方法。這也是為什么上面我需要去判斷輸入參數的數量以及類型的緣故。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
日韩午夜在线视频| 日韩电影网在线| 这里只有精品在线播放| 欧美午夜视频在线观看| 亚洲国产成人av在线| 欧美与黑人午夜性猛交久久久| 国产婷婷97碰碰久久人人蜜臀| 欧美亚洲激情视频| 国产日韩视频在线观看| 国产成人一区二区三区小说| 国产精品黄页免费高清在线观看| 91av视频在线| 色琪琪综合男人的天堂aⅴ视频| 午夜精品一区二区三区在线播放| 精品久久久久久久久久久久久| 51视频国产精品一区二区| 亚洲免费伊人电影在线观看av| 国产成人综合亚洲| 韩国三级日本三级少妇99| 日韩亚洲欧美中文在线| 日韩网站免费观看| 日韩成人在线观看| 日韩av三级在线观看| 亚洲激情成人网| 成人国产精品久久久久久亚洲| 精品久久久久久久久中文字幕| 欧美激情伊人电影| 2021久久精品国产99国产精品| 国产精品视频yy9099| 国产丝袜高跟一区| 欧美性视频在线| 欧美一级淫片videoshd| 国产精品一久久香蕉国产线看观看| 久久精品久久久久久| 中文字幕自拍vr一区二区三区| 亚洲成**性毛茸茸| 2019国产精品自在线拍国产不卡| 国产欧美日韩亚洲精品| 国产欧美亚洲精品| 91香蕉嫩草影院入口| 狠狠做深爱婷婷久久综合一区| 91夜夜揉人人捏人人添红杏| 国产日韩精品视频| 国产黑人绿帽在线第一区| 中文精品99久久国产香蕉| 欧美xxxx做受欧美| 麻豆成人在线看| 日韩国产在线看| 国产综合香蕉五月婷在线| 精品网站999www| 中文字幕欧美日韩| 韩剧1988在线观看免费完整版| 俺去啦;欧美日韩| 日韩av网址在线| 欧美高清视频一区二区| 国产成人黄色av| www.亚洲免费视频| 亚洲精品日韩av| 精品久久久久久国产| 97视频com| xxxx欧美18另类的高清| 伊人精品在线观看| 国产日韩欧美中文| 久久久久久久久91| 国产精品福利无圣光在线一区| 日韩美女福利视频| 欧美黄色小视频| 77777亚洲午夜久久多人| 热门国产精品亚洲第一区在线| 久久亚洲私人国产精品va| 欧美日韩一区二区精品| 久久久久久久久久国产| 97婷婷大伊香蕉精品视频| 亚洲www在线| 7777精品久久久久久| 亚洲www在线| 精品亚洲国产成av人片传媒| 日本在线观看天堂男亚洲| 国产精品久久久久久久一区探花| 国产一区二区三区在线观看视频| 国产99久久精品一区二区永久免费| 国产福利成人在线| 成人黄色在线观看| 成人欧美一区二区三区黑人孕妇| 国产精品狼人色视频一区| 亚洲精品国产欧美| 米奇精品一区二区三区在线观看| 97视频免费观看| 亚洲天堂av电影| 亚洲一区二区自拍| 国产精品揄拍一区二区| 久久久久久亚洲精品不卡| 亚洲天堂日韩电影| 国产精品自产拍在线观看| 亚洲aaa激情| 亚洲摸下面视频| 国产成人自拍视频在线观看| 在线电影欧美日韩一区二区私密| 国产综合久久久久| 久久久精品久久久| 欧美理论在线观看| 国产精品久久精品| 久久久久久久久久国产精品| 成人深夜直播免费观看| 麻豆国产精品va在线观看不卡| 日韩精品极品在线观看| 亚洲xxxxx性| 精品久久久久久久久久久久久久| 中文字幕日韩视频| 国产97在线亚洲| 久久久久久久国产精品| 日韩电影在线观看免费| 日韩女优人人人人射在线视频| 欧美日韩成人精品| 亚洲综合中文字幕在线| 成人黄色中文字幕| 久久久亚洲福利精品午夜| 91在线看www| 国产精品入口夜色视频大尺度| 亚洲精品一区中文| 国产精品99久久久久久久久久久久| 欧美电影免费观看高清完整| 国产69精品久久久| 亚洲欧美另类人妖| 亚洲欧美日韩一区二区三区在线| 亚洲欧美制服另类日韩| 91亚洲午夜在线| 国产亚洲精品一区二区| 亚洲淫片在线视频| 亚洲free性xxxx护士hd| 国产精品一香蕉国产线看观看| 久久亚洲精品一区二区| 成人久久一区二区三区| 久久精品欧美视频| 91精品国产自产在线观看永久| 成人黄色大片在线免费观看| 国产97在线|日韩| 欧美国产视频一区二区| 成人在线观看视频网站| 国产91色在线| 日韩中文有码在线视频| 狠狠躁夜夜躁人人爽天天天天97| 欧美精品videossex88| 在线看日韩欧美| 57pao国产成人免费| 成人免费看黄网站| 国产一区视频在线| 亚洲免费av电影| 亚洲在线观看视频| 91精品视频大全| 欧美一区二区视频97| 欧美性色19p| 国内揄拍国内精品少妇国语| 最近2019中文字幕第三页视频| 亚洲色图综合网| 羞羞色国产精品| 久久精品一区中文字幕| 亚洲美女精品久久| 美日韩精品免费视频| 欧美成人在线免费| 久久久久久91| 国产aaa精品| 亚洲最新av在线网站| 国产在线视频不卡|