欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C#反射機(jī)制介紹

 更新時(shí)間:2022年03月07日 10:03:28   作者:.NET開(kāi)發(fā)菜鳥(niǎo)  
這篇文章介紹了C#的反射機(jī)制,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

先看下面一個(gè)動(dòng)物點(diǎn)名系統(tǒng)的簡(jiǎn)單例子:

有一個(gè)Animal的抽象動(dòng)物父類(lèi),里面定義了Name、Age兩個(gè)屬性和一個(gè)Shout()方法,Animal類(lèi)定義如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Animal
{
    /// <summary>
    /// 抽象父類(lèi)
    /// </summary>
    public abstract class Animal
    {
        /// <summary>
        /// Name屬性
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// Age屬性
        /// </summary>
        public int Age { get; set; }

        /// <summary>
        /// Shout抽象方法
        /// </summary>
        public abstract void Shout();
    }
}

分別定義Cat、Dog類(lèi)繼承自Animal類(lèi),Cat類(lèi)定義如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Animal
{
    public class Cat :Animal
    {
        /// <summary>
        /// 構(gòu)造函數(shù)初始化
        /// </summary>
        public Cat()
        {
            base.Name = "湯姆";
            base.Age = 2;
        }

        public override void Shout()
        {
            Console.WriteLine("喵喵喵,我是{0},今年{1}歲",
                base.Name,base.Age);
        }
    }
}

Dog類(lèi)定義如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Animal
{
    public class Dog : Animal
    {
        /// <summary>
        /// 構(gòu)造函數(shù)初始化
        /// </summary>
        public Dog()
        {
            base.Name = "布魯斯";
            base.Age = 3;
        }

        public override void Shout()
        {
            Console.WriteLine("汪汪汪,我是{0},今年{1}歲",
                base.Name, base.Age);
        }
    }
}

應(yīng)用場(chǎng)景:在一個(gè)控制臺(tái)程序中,輸入具體的動(dòng)物的類(lèi)型,根據(jù)輸入的動(dòng)物類(lèi)型,輸出Name、Age和Shout()方法,使用傳統(tǒng)方式實(shí)現(xiàn)的代碼如下:

using Animal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;


namespace ReflectionCon
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("請(qǐng)錄入動(dòng)物類(lèi)型:");
            string type = Console.ReadLine().Trim();

            Animal.Animal a = null;
            switch (type)
            {
                case "cat":
                    a = new Cat();
                    a.Shout();
                    break;
                case "dog":
                    a = new Cat();
                    a.Shout();
                    break;
            }
            Console.ReadKey();
        }
    }
}

程序運(yùn)行結(jié)果如下:

那么問(wèn)題來(lái)了:如果我們想要增加一個(gè)動(dòng)物類(lèi)型,那么就需要修改現(xiàn)有的代碼,在switch里面增加判斷。但是這種方式很不利于以后的維護(hù),違反了開(kāi)閉原則,每次增加一個(gè)動(dòng)物類(lèi)型的時(shí)候,都需要修改代碼。那么有沒(méi)有其他方式可以做到不用修改代碼就可以實(shí)現(xiàn)呢?答案是肯定的,那就是使用我們接下來(lái)要講的反射,先來(lái)了解一下什么是反射。

一、什么是反射

在講解什么是反射之前,先來(lái)了解應(yīng)用程序的結(jié)構(gòu)。

程序代碼在編譯后生成可執(zhí)行的應(yīng)用,我們首先要了解這種可執(zhí)行應(yīng)用程序的結(jié)構(gòu)。

應(yīng)用程序結(jié)果分為應(yīng)用程序域-程序集-模塊-類(lèi)型-成員幾個(gè)層次,公共語(yǔ)言運(yùn)行時(shí)(CLR)加載器管理應(yīng)用程序域,這種管理包括將每個(gè)程序集加載到相應(yīng)的應(yīng)用程序域以及控制每個(gè)程序集中類(lèi)型層次結(jié)構(gòu)的內(nèi)存布局。

程序集包含模塊,而模塊包含類(lèi)型,類(lèi)型又包含成員,反射則提供了封裝程序集、模塊和類(lèi)型的對(duì)象。我們可以使用反射動(dòng)態(tài)地創(chuàng)建類(lèi)型的實(shí)例,將類(lèi)型綁定到現(xiàn)有對(duì)象或從現(xiàn)有對(duì)象中獲取類(lèi)型,然后調(diào)用類(lèi)型的方法或訪問(wèn)其字段和屬性。

那么究竟什么是反射呢?

反射(Reflection)是.NET中的重要機(jī)制,可以在運(yùn)行時(shí)獲得.NET中每一個(gè)類(lèi)型(包括類(lèi)、結(jié)構(gòu)、委托、接口和枚舉等)的成員,包括方法、屬性、事件、以及構(gòu)造函數(shù)等。還可以獲得每個(gè)成員的名稱、限定符和參數(shù)等。有了反射,即可對(duì)每一個(gè)類(lèi)型了如指掌。如果獲得了構(gòu)造函數(shù)的信息,即可直接創(chuàng)建對(duì)象,即使這個(gè)對(duì)象的類(lèi)型在編譯時(shí)還不知道。

二、反射的用途

1、使用Assembly定義和加載程序集,加載在程序集清單中列出模塊,以及從此程序集中查找類(lèi)型并創(chuàng)建該類(lèi)型的實(shí)例。

2、使用Module了解包含模塊的程序集以及模塊中的類(lèi)等,還可以獲取在模塊上定義的所有全局方法或其他特定的非全局方法。

3、使用ConstructorInfo了解構(gòu)造函數(shù)的名稱、參數(shù)、訪問(wèn)修飾符(如public或private)和實(shí)現(xiàn)詳細(xì)信息(如abstract或virtual)等。使用Type的GetConstructors()或GetConstructor()方法來(lái)調(diào)用特定的構(gòu)造函數(shù)。

4、使用MethodInfo了解方法的名稱,返回類(lèi)型、參數(shù)、訪問(wèn)修飾符(如public或private)和實(shí)現(xiàn)詳細(xì)信息(如abstract或virtual)等。使用Type的GetMethods()或GetMethod()方法來(lái)調(diào)用特定的方法。

5、使用FiledInfo了解字段的名稱、訪問(wèn)修飾符(如public或private)和實(shí)現(xiàn)詳細(xì)信息(如static)等,并獲取或設(shè)置字段值。

6、使用EventInfo了解事件的名稱、事件處理程序數(shù)據(jù)類(lèi)型、自定義屬性、聲明類(lèi)型和反射類(lèi)型等,添加或移除事件處理程序。

7、使用PropertyInfo了解屬性的名稱、數(shù)據(jù)類(lèi)型、聲明類(lèi)型、反射類(lèi)型和只讀或可寫(xiě)狀態(tài)等,獲取或設(shè)置屬性值。

8、使用ParameterInfo了解參數(shù)的名稱、數(shù)據(jù)類(lèi)型、是輸入?yún)?shù)還是輸出參數(shù),以及參數(shù)在方法簽名中的位置等。

三、反射用到的命名空間及主要類(lèi)

1、命名空間

System.Reflection
System.Type
System.Reflection.Assembly

2、反射用到的主要類(lèi)

Type類(lèi):該類(lèi)位于System.Type命名空間下面,通過(guò)這個(gè)類(lèi)可以訪問(wèn)任何給定數(shù)據(jù)類(lèi)型的信息。

Assembly類(lèi):該類(lèi)位于System.Reflection.Assembly命名空間下面,通過(guò)這個(gè)類(lèi)可以訪問(wèn)給定程序集的信息,或者把這個(gè)程序集加載到程序中。

四、Type類(lèi)

Type類(lèi)位于System.Type命名空間下面,通過(guò)這個(gè)類(lèi)可以訪問(wèn)關(guān)于任何數(shù)據(jù)類(lèi)型的信息。

我們以前把Type看作一個(gè)類(lèi),但它實(shí)際上是一個(gè)抽象的基類(lèi)。只要實(shí)例化了一個(gè)Type對(duì)象,實(shí)際上就實(shí)例化了Type的一個(gè)派生類(lèi)。盡管一般情況下派生類(lèi)只提供各種Type方法和屬性的不同重載,但是這些方法和屬性返回對(duì)應(yīng)數(shù)據(jù)類(lèi)型的正確數(shù)據(jù),Type有與每種數(shù)據(jù)類(lèi)型對(duì)應(yīng)的派生類(lèi)。

它們一般不添加新的方法或?qū)傩?。通?獲取指向任何給定類(lèi)型的Type引用有3種常用方式:

1、使用GetType()方法,所有的類(lèi)都會(huì)從System.Object繼承這個(gè)方法

string v = "abc";
Type type = v.GetType();

2、使用Type類(lèi)的靜態(tài)方法GetType()

Type type2 = Type.GetType("System.string", false, true);

3、使用C#的typeof運(yùn)算符,這個(gè)運(yùn)算符的參數(shù)是類(lèi)型的名稱(但不放在引號(hào)中)

var t = typeof(string);

運(yùn)行結(jié)果:

注意:在一個(gè)變量上調(diào)用GetType()方法,不是把類(lèi)型的名稱作為其參數(shù)。但要注意,返回的Type對(duì)象仍只與該數(shù)據(jù)類(lèi)型相關(guān)。如果引用了一個(gè)對(duì)象,但不能確保該對(duì)象實(shí)際上是哪個(gè)類(lèi)型的實(shí)例,這個(gè)方法就很有用。

4、Type類(lèi)的屬性

由Type實(shí)現(xiàn)的屬性可以分為下述三類(lèi):

1)許多屬性都可以獲取包含與類(lèi)相關(guān)的各種名稱的字符串

2)屬性還可以進(jìn)一步獲取Type對(duì)象的引用,這些引用表示相關(guān)的類(lèi)

3)許多Boolean 屬性表示這個(gè)類(lèi)型是一個(gè)類(lèi)、還是一個(gè)枚舉等。這些屬性包括IsAbstract、IsArray、IsClass、IsEnum、IsInterface、IsPointer、IsPrimitive(一種預(yù)定義的基本數(shù)據(jù)類(lèi)型)、 IsPublic、IsSealed和IsValueType

5、Type類(lèi)的方法

System.Type類(lèi)的大多數(shù)方法都用于獲取對(duì)應(yīng)數(shù)據(jù)類(lèi)型的成員信息:構(gòu)造函數(shù)、屬性、方法和事件等。它有許多方法,但它們都有相同的模式。

例如,有兩個(gè)方法可以獲取數(shù)據(jù)類(lèi)型的方法信息:GetMethod() 和 GetMethods()。GetMethod()方法返回System.Reflection.MethodInfo對(duì)象的一個(gè)引用,其中包含一個(gè)方法的信息。GetMethods()返回這種引用的一個(gè)數(shù)組。其區(qū)別是GetMethods()返回所有方法的信息,而GetMethod()返回一個(gè)方法的信息,其中該方法包含特定的參數(shù)列表。這兩個(gè)方法都有重載方法,該重載方法有一個(gè)附加的參數(shù),BindingFlags枚舉值,表示應(yīng)返回哪些成員,例如,返回公有成員、實(shí)例成員和靜態(tài)成員等。

Type的成員方法:

注意:GetMember() 和 GetMembers()方法返回?cái)?shù)據(jù)類(lèi)型的一個(gè)或所有成員的信息,這些成員可以是構(gòu)造函數(shù)、屬性和方法等。最后要注意,可以調(diào)用這些成員,其方式是調(diào)用Type的InvokeMember()方法,或者調(diào)用MethodInfo, PropertyInfo和其他類(lèi)的Invoke()方法。

五、Assembly類(lèi)

Assembly類(lèi)在System.Reflection名稱空間中定義,它允許訪問(wèn)給定程序集的元數(shù)據(jù),它也包含可以加載和執(zhí)行程序集(假定該程序集是可執(zhí)行的)的方法。與Type類(lèi)一樣,Assembly類(lèi)包含非常多的方法和屬性。

在使用Assembly實(shí)例做一些工作前,需要把相應(yīng)的程序集加載到正在運(yùn)行的進(jìn)程中。為此,可以使用靜態(tài)成員Assembly.Load()或Assembly.LoadFrom()這兩個(gè)方法的區(qū)別是:

Load()方法的參數(shù)是程序集的名稱,運(yùn)行庫(kù)會(huì)在各個(gè)位置上搜索該程序集,試圖找到該程序集,這些位置包括本地目錄和全局程序集緩存。使用Load()方法前要添加程序集的引用。

LoadFrom()方法的參數(shù)是程序集的完整路徑名,它不會(huì)在其他位置搜索該程程序集。

例如:

Assembly assembly1 = Assembly.Load("Animal");
Assembly assembly1 = Assembly.LoadFrom(@"D:\Study\Practice\Animal.dll");

這兩個(gè)方法都有許多其他重載版本,它們提供了其他安全信息。加載了一個(gè)程序集后,就可以使用它的各種屬性進(jìn)行查詢,例如,查找它的全名:

string name = assembly1.FullName;

Assembly類(lèi)的一個(gè)功能是它可以獲得在相應(yīng)程序集中定義的所有類(lèi)型的詳細(xì)信息,只要調(diào)用Assembly以GetTypes()方法,它就可以返回一個(gè)包含所有類(lèi)型的詳細(xì)信息的Type類(lèi)型的引用數(shù)組:

Type[] types = assembly.GetTypes();
foreach (Type definedType in types)
(
  //處理代碼
)

六、使用反射實(shí)現(xiàn)上面的程序

經(jīng)過(guò)上面的講解,相信大家對(duì)反射有一定的了解了,下面將會(huì)使用反射實(shí)現(xiàn)開(kāi)篇提到的應(yīng)用場(chǎng)景,代碼如下:

using Animal;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;


namespace ReflectionCon
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("請(qǐng)錄入動(dòng)物類(lèi)型:");
            string type = Console.ReadLine().Trim();

            // 創(chuàng)建程序集對(duì)象,靜態(tài)加載Animal程序集  前提:需要先添加對(duì)Animal程序集的引用
            Assembly assembly = Assembly.Load("Animal");
            // 獲取程序集中的類(lèi)型(在這里指的就是Animal里面的類(lèi):即Cat、Dog、Pig、Bird類(lèi))
            Type[] types = assembly.GetTypes();
            foreach (Type t in types)
            {
                // t.Name表示類(lèi)名(即Cat、Dog、Pig、Bird)
                if (type == t.Name.ToLower())
                {
                    // 找到Shout方法
                    MethodInfo m = t.GetMethod("Shout");
                    // 創(chuàng)建對(duì)象
                    object o = Activator.CreateInstance(t);

                    // 找屬性
                    PropertyInfo[] para = t.GetProperties();
                    // 遍歷屬性
                    foreach (PropertyInfo p in para)
                    {
                        // 輸出屬性的名字 即:Name和Age
                        //Console.WriteLine(p.Name);
                        if (p.Name == "Name")
                        {
                            // 給屬性賦值
                            p.SetValue(o, "張三", null);
                        }
                        if (p.Name == "Age")
                        {
                            // 獲取o對(duì)象的屬性為p的屬性值并加10
                            int age = Convert.ToInt32(p.GetValue(o)) + 10;
                            // 給屬性賦值
                            p.SetValue(o, age, null);
                        }
                    }

                    // 調(diào)用方法
                    m.Invoke(o, null);
                }
            }

            Console.ReadKey();
        }
    }
}

運(yùn)行程序:

如果新增加一個(gè)動(dòng)物類(lèi),只需要實(shí)現(xiàn)Animal抽象父類(lèi)即可,而主程序不需要修改。

七、反射的優(yōu)缺點(diǎn)

1、反射的優(yōu)點(diǎn)

1)、反射提高了程序的靈活性和擴(kuò)展性。
2)、降低耦合性,提高自適應(yīng)能力。
3)、它允許程序動(dòng)態(tài)創(chuàng)建和控制任何類(lèi)的對(duì)象,無(wú)需提前硬編碼目標(biāo)類(lèi)。適用在程序集不固定的地方,通常和配置文件一起使用。

2、反射的缺點(diǎn)

1)、性能問(wèn)題:使用反射基本上是一種解釋操作,用于字段和方法接入時(shí)要遠(yuǎn)慢于直接代碼。因此反射機(jī)制主要應(yīng)用在對(duì)靈活性和拓展性要求很高的系統(tǒng)框架上,普通程序不建議使用。
2)、使用反射會(huì)模糊程序內(nèi)部邏輯;程序員希望在源代碼中看到程序的邏輯,反射卻繞過(guò)了源代碼的技術(shù),因而會(huì)帶來(lái)維護(hù)的問(wèn)題,反射代碼比相應(yīng)的直接代碼更復(fù)雜。

到此這篇關(guān)于C#反射機(jī)制的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • WPF+ASP.NET?SignalR實(shí)現(xiàn)簡(jiǎn)易在線聊天功能的示例代碼

    WPF+ASP.NET?SignalR實(shí)現(xiàn)簡(jiǎn)易在線聊天功能的示例代碼

    這篇文章將以一個(gè)簡(jiǎn)單的聊天示例,簡(jiǎn)述如何通過(guò)WPF+ASP.NET?SignalR實(shí)現(xiàn)消息后臺(tái)通知,僅供學(xué)習(xí)分享使用,如有不足之處,還請(qǐng)指正
    2022-09-09
  • 最新評(píng)論