程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 淺顯易懂的C#之反射教程

淺顯易懂的C#之反射教程

編輯:C#入門知識

淺顯易懂的C#之反射教程。本站提示廣大學習愛好者:(淺顯易懂的C#之反射教程)文章只能為提供參考,不一定能成為您想要的結果。以下是淺顯易懂的C#之反射教程正文


媒介

之所以要寫這篇關於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,你能夠會以為它們不是屬性嗎?怎樣跑到辦法這裡來了,其實下面我曾經說了。這些其實也是辦法。這也是為何下面我須要去斷定輸出參數的數目和類型的原因。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved