最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時間:2015年01月28日 11:51:48   投稿:junjie  
這篇文章主要介紹了通俗易懂的C#之反射教程,本文深入分析了反射內(nèi)部的原理,剖析了內(nèi)部屬性、方法的運(yùn)作,并用通俗易懂的語言闡述,需要的朋友可以參考下

前言

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

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

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

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

前期準(zhǔn)備

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

復(fù)制代碼 代碼如下:

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

            public void Show()
            {

            }
        }

窺視內(nèi)部

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

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

復(fù)制代碼 代碼如下:

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

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

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

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

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

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

復(fù)制代碼 代碼如下:

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的重載版本,并且傳入了枚舉類型,分別是“包含非公開”、“包含實例成員”和“包含公開”。然后我們就可以獲取到所有成員了。

 

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

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

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

復(fù)制代碼 代碼如下:

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

然后我們再查看結(jié)果:

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

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

復(fù)制代碼 代碼如下:

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()
            {

            }
        }

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

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

復(fù)制代碼 代碼如下:

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();
        }

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

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

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

深入窺視字段

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

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

復(fù)制代碼 代碼如下:

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();
        }

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

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

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

復(fù)制代碼 代碼如下:

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();
        }

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

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

復(fù)制代碼 代碼如下:

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),下面我們繼續(xù)看最終輸出的結(jié)果:

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

深入窺視屬性

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

比如下面的代碼:

復(fù)制代碼 代碼如下:

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}  參數(shù)數(shù)量:{2}  MSIL代碼長度:{3} 局部變量數(shù)量:{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}  參數(shù)數(shù)量:{2}  MSIL代碼長度:{3} 局部變量數(shù)量:{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}  內(nèi)部值:{1}", finfo.Name, obj);
            }
            Console.ReadKey();
        }

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

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

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

深入窺視方法

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

復(fù)制代碼 代碼如下:

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;
            }
        }

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

下面我們直接上代碼:

復(fù)制代碼 代碼如下:

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("擁有參數(shù)的方法名:{0}  返回值類型:{1}  參數(shù)1類型:{2}  參數(shù)1名稱:{3}  方法調(diào)用后返回的值:{4}",
                        finfo.Name,
                        finfo.ReturnType.ToString(),
                        finfo.GetParameters()[0].ParameterType.ToString(),
                        finfo.GetParameters()[0].Name,
                        obj.ToString());
                }
                else
                {
                    MethodBody mbody = finfo.GetMethodBody();
                    Console.WriteLine("沒有參數(shù)的方法名:{0}  返回值類型:{1}",
                        finfo.Name,
                        finfo.ReturnType.ToString());
                }
            }
            Console.ReadKey();
        }

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

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

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

相關(guān)文章

  • C#.Net ArrayList的使用方法

    C#.Net ArrayList的使用方法

    這篇文章主要介紹了C#.Net ArrayList的使用方法,使用動態(tài)數(shù)組的優(yōu)點是可以根據(jù)用戶需要,有效利用存儲空間,需要的朋友可以參考下
    2015-10-10
  • LINQ基礎(chǔ)之Intersect、Except和Distinct子句

    LINQ基礎(chǔ)之Intersect、Except和Distinct子句

    這篇文章介紹了LINQ使用Intersect、Except和Distinct子句的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • C#多維數(shù)組學(xué)習(xí)使用

    C#多維數(shù)組學(xué)習(xí)使用

    當(dāng)下, 由于存儲結(jié)構(gòu)需要, 用多維數(shù)組, 順便學(xué)習(xí)了一下, 將學(xué)習(xí)經(jīng)過備忘如下
    2012-09-09
  • C# 一個WCF簡單實例

    C# 一個WCF簡單實例

    以訂票為例簡單應(yīng)用wcf程序,需要的朋友可以參考下
    2012-10-10
  • C#創(chuàng)建不規(guī)則窗體的4種方式詳解

    C#創(chuàng)建不規(guī)則窗體的4種方式詳解

    在這里我們將實現(xiàn)的是C#創(chuàng)建不規(guī)則窗體的幾種方式,包括自定義窗體,不規(guī)則圖形等等。希望對大家有所幫助。
    2015-10-10
  • WPF實現(xiàn)環(huán)(圓)形菜單的示例代碼

    WPF實現(xiàn)環(huán)(圓)形菜單的示例代碼

    這篇文章主要介紹了如何利用WPF繪制一個簡單的環(huán)形菜單,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)或工作有一定幫助,需要的可以參考一下
    2022-07-07
  • c#和net存取cookies操作示例

    c#和net存取cookies操作示例

    這篇文章主要介紹了c#和net存取cookies操作示例,需要的朋友可以參考下
    2014-02-02
  • C#實現(xiàn)簡單超市收銀系統(tǒng)

    C#實現(xiàn)簡單超市收銀系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C#實現(xiàn)簡單超市收銀系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • C#實現(xiàn)Datatable排序的方法

    C#實現(xiàn)Datatable排序的方法

    這篇文章主要介紹了C#實現(xiàn)Datatable排序的方法,在進(jìn)行C#數(shù)據(jù)庫程序設(shè)計的時候有不錯的借鑒價值,需要的朋友可以參考下
    2014-09-09
  • 使用C#獲取網(wǎng)頁HTML源碼的例子

    使用C#獲取網(wǎng)頁HTML源碼的例子

    這篇文章主要介紹了使用C#獲取網(wǎng)頁HTML源碼的例子,考慮了區(qū)分GB2312和UTF-8編碼,需要的朋友可以參考下
    2014-08-08

最新評論

和林格尔县| 浦东新区| 天气| 邵武市| 阳高县| 准格尔旗| 磴口县| 崇明县| 库车县| 齐齐哈尔市| 大邑县| 故城县| 大英县| 东城区| 淮阳县| 仙游县| 博湖县| 朝阳县| 浏阳市| 泸西县| 灌阳县| 曲麻莱县| 津市市| 封开县| 雅安市| 姚安县| 寻甸| 淮南市| 黑河市| 满城县| 铜鼓县| 漯河市| 汶上县| 哈尔滨市| 哈巴河县| 巍山| 读书| 米脂县| 云龙县| 康平县| 湘阴县|