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

首頁 > 學院 > 開發設計 > 正文

.Net 中的反射(動態創建類型實例)

2019-11-11 04:24:19
字體:
來源:轉載
供稿:網友

動態創建對象

在前面節中,我們先了解了反射,然后利用反射查看了類型信息,并學習了如何創建自定義特性,并利用反射來遍歷它??梢哉f,前面三節,我們學習的都是反射是什么,在接下來的章節中,我們將學習反射可以做什么。在進行更有趣的話題之前,我們先看下如何動態地創建一個對象。

我們新建一個Console控制臺項目,叫做Reflection4(因為本文是Part4,你也可以起別的名字)。然后,添加一個示范類,本文中將通過對這個示范類的操作來進行說明:

public class Calculator {    PRivate int x;    private int y;    public Calculator(){       x = 0;       y = 0;    }    public Calculator(int x,int y) {       this.x = x;       this.y = y;    }}

1.使用無參數構造函數創建對象

上面這個類非常簡單,它包含兩個構造函數,一個是有參數的構造函數,一個是無參數的構造函數,我們先看看通過反射,使用無參數的構造函數創建對象。創建對象通常有兩種方式,一種是使用Assembly的CreateInstance方法:

Assembly asm = Assembly.GetExecutingAssembly();          Object obj = asm.CreateInstance("Reflection4.Calculator",true);// 輸出:Calculator() invoked

CreateInstance的第一個參數代表了要創建的類型實例的字符串名稱,第二個參數說明是不是大小寫無關(Ignore Case)。注意到CreateInstance返回的是一個Object對象,意味著如果想使用這個對象,需要進行一次類型轉換。

創建對象的另一種方式是調用Activator類的靜態方法CreateInstance:

ObjectHandle handler = Activator.CreateInstance(null,"Reflection4.Calculator");Object obj = handler.Unwrap();

其中CreateInstance的第一個參數說明是程序集的名稱,為null時表示當前程序集;第二個參數說明要創建的類型名稱。Activator.CreateInstance返回的是一個ObjectHandle對象,必須進行一次Unwrap()才能返回Object類型,進而可以強制轉換成我們需要的類型(本例中是Calculator)。ObjectHandle包含在System.Runtime.Remoting命名空間中,可見它是Remoting相關的,實際上ObjectHandle類只是一個對原類型進行了一個包裝以便進行封送,更多內容可以參見.Net Remoting(應用程序域)—Part.1 這篇文章。

2.使用有參數構造函數創建對象

如果我們想通過有參數的構造函數創建對象,我們可以使用Assembly的CreateInstanc()的重載方法:

// 有參數構造函數創建對象Assembly asm = Assembly.GetExecutingAssembly();Object[] parameters = new Object[2];    // 定義構造函數需要的參數parameters[0] = 3;parameters[1] = 5;Object obj = asm.CreateInstance("Reflection4.Calculator",true, BindingFlags.Default, null, parameters, null, null);// 輸出:Calculator(int x,int y) invoked

我們看一下CreateInstance需要提供的參數:

前兩個在前一小節已經說明過了;BindingFlags在前面我們也用到過,它用于限定對類型成員的搜索。在這里指定Default,意思是不使用BingdingFlags的策略(你可以把它理解成null,但是BindingFlags是值類型,所以不可能為null,必須有一個默認值,而這個Default就是它的默認值);接下來的參數是Binder,它封裝了CreateInstance綁定對象(Calculator)的規則,我們幾乎永遠都會傳遞null進去,實際上使用的是預定義的DefaultBinder;接下來是一個Object[]數組類型,它包含我們傳遞進去的參數,有參數的構造函數將會使用這些參數;接下來的參數是一個CultureInfo類型,它包含了關于語言和文化的信息(簡單點理解就是什么時候ToString("c")應該顯示“¥”,什么時候應該顯示“$”)。

動態調用方法

接下來我們看一下如何動態地調用方法。注意,本文討論的調用不是將上面動態創建好的對象由Object類型轉換成Calculator類型再進行方法調用,這和“常規調用”就沒有區別了,讓我們以.Net Reflection 的方式來進行方法的調用。繼續進行之前,我們為Calculator添加兩個方法,一個實例方法,一個靜態方法:

public int Add(){    int total= 0;    total = x + y;    Console.WriteLine("Invoke Instance Method: ");    Console.WriteLine(String.Format("[Add]: {0} plus {1} equals to {2}", x, y, total));    return total;}public staticvoid Add(int x,int y){    int total = x + y;    Console.WriteLine("Invoke Static Method: ");    Console.WriteLine(String.Format("[Add]: {0} plus {1} equals to {2}", x, y, total));}

調用方法的方式一般有兩種:

在類型的Type對象上調用InvokeMember()方法,傳遞想要在其上調用方法的對象(也就是剛才動態創建的Calculator類型實例),并指定BindingFlags為InvokeMethod。根據方法簽名,可能還需要傳遞參數。先通過Type對象的GetMethond()方法,獲取想要調用的方法對象,也就是MethodInfo對象,然后在該對象上調用Invoke方法。根據方法簽名,可能還需要傳遞參數。

需要說明的是,使用InvokeMember不限于調用對象的方法,也可以用于獲取對象的字段、屬性,方式都是類似的,本文只說明最常見的調用方法。

1.使用InvokeMember調用方法

我們先看第一種方法,代碼很簡單,只需要兩行(注意obj在上節已經創建,是Calculator類型的實例):

Type t = typeof(Calculator);int result = (int)t.InvokeMember("Add", BindingFlags.InvokeMethod,null, obj, null);Console.WriteLine(String.Format("The resultis {0}", result));輸出:Invoke Instance Method:[Add]: 3 plus 5 equals to 8The result is 8

在InvokeMember方法中,第一個參數說明了想要調用的方法名稱;第二個參數說明是調用方法(因為InvokeMember的功能非常強大,不光是可以調用方法,還可以獲取/設置 屬性、字段等。此枚舉的詳情可參看Part.2或者MSDN);第三個參數是Binder,null說明使用默認的Binder;第四個參數說明是在這個對象上(obj是Calculator類型的實例)進行調用;最后一個參數是數組類型,表示的是方法所接受的參數。

我們在看一下對于靜態方法應該如何調用:

Object[] parameters2 = new Object[2];parameters2[0] = 6;parameters2[1] = 9;t.InvokeMember("Add", BindingFlags.InvokeMethod,null, typeof(Calculator), parameters2);輸出:Invoke Static Method:[Add]: 6 plus 9 equals to 15

我們和上面對比一下:首先,第四個參數傳遞的是 typeof(Calculator),不再是一個Calculator實例類型,這很容易理解,因為我們調用的是一個靜態方法,它不是基于某個具體的類型實例的,而是基于類型本身;其次,因為我們的靜態方法需要提供兩個參數,所以我們以數組的形式將這兩個參數進行了傳遞。

2.使用MethodInfo.Invoke調用方法

我們再看下第二種方式,先獲得一個MethodInfo實例,然后調用這個實例的Invoke方法,我們看下具體如何做:

Type t = typeof(Calculator);MethodInfo mi = t.GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);mi.Invoke(obj, null);輸出:Invoke Instance Method:[Add]: 3 plus 5 equals to 8請按任意鍵繼續. . .

在代碼的第二行,我們先使用GetMethod方法獲取了一個方法對象MethodInfo,指定BindingFlags為Instance和Public,因為有兩個方法都命名為“Add”,所以在這里指定搜索條件是必須的。接著我們使用Invoke()調用了Add方法,第一個參數obj是前面創建的Calculator類型實例,表明在該實例上創建方法;第二個參數為null,說明方法不需要提供參數。

我們再看下如何使用這種方式調用靜態方法:

Type t = typeof(Calculator);Object[] parameters2 = new Object[2];parameters2[0] = 6;parameters2[1] = 9;MethodInfo mi = t.GetMethod("Add", BindingFlags.Static | BindingFlags.Public);mi.Invoke(null, parameters2);// mi.Invoke(t, parameters2);   也可以這樣輸出:Invoke Static Method:[Add]: 6 plus 9 equals to 15

可以看到與上面的大同小異,在GetMethod()方法中,我們指定為搜索BindingFlags.Static,而不是BindingFlags.Public,因為我們要調用的是靜態的Add方法。在Invoke()方法中,需要注意的是第一個參數,不能在傳遞Calculator類型實例,而應該傳遞Calculator的Type類型或者直接傳遞null。因為靜態方法不是屬于某個實例的。

NOTE:通過上面的例子可以看出:使用反射可以達到最大程度上的多態,舉個例子,你可以在頁面上放置一個DropDownList控件,然后指定它的Items的value為你某個類的方法的名稱,然后在SelectedIndexChanged事件中,利用value的值來調用類的方法。而在以前,你只能寫一些if else 語句,先判斷DropDownList返回的值,根據值再決定調用哪個方法。使用這種方式,編譯器在代碼運行之前(或者說用戶選擇了某個選項之前)完全不知道哪個方法將被調用,這也就是常說的遲綁定(Late Binding)

Coding4Fun:遍歷System.Drawing.Color結構

我們已經講述了太多的基本方法和理論,現在讓我們來做一點有趣的事情:大家知道在asp.net中控件的顏色設置,比如說ForeColor, BackColor等,都是一個System.Draw.Color結構類型。在某些情況下我們需要使用自定義的顏色,那么我們會使用類似這樣的方式Color.FromRgb(125,25,13)創建一個顏色值。但有時候我們會覺得比較麻煩,因為這個數字太不直觀了,我們甚至需要把這個值貼到photoshop中看看是什么樣的。

這時候,我們可能會想要使用Color結構提供的默認顏色,也就是它的141個靜態屬性,但是這些值依然是以名稱,比如DarkGreen的形式給出的,還是不夠直觀,如果能把它們以色塊的形式輸出到頁面就好了,這樣我們查看起來會方便的多,以后使用也會比較便利。我已經實現了它,可以點擊下面的鏈接查看:

效果預覽:http://www.tracefact.net/demo/reflection/color.aspx

基本實現

現在我們來看一下實現過程:

先創建頁面Color.aspx(或其他名字),然后在Head里添加些樣式控制頁面顯示,再拖放一個Panel控件進去。樣式表需要注意的是#pnColors div部分,它定義了頁面上將顯示的色塊的樣式;Id為pnHolder的Panel控件用于裝載我們動態生成的div。

<head><style type="text/CSS">body{font-size:14px;}h1{font-size:26px;}#pnColors div{    float:left;width:140px;    padding:7px 0;    text-align:center;    margin:3px;     border:1px solid #aaa;    font-size:11px;    font-family:verdana, arial}</style></head><body>    <h1>Coding4Fun:使用反射遍歷System.Drawing.Color結構</h1>    <form id="form1" runat="server">       <asp:Panel ID="pnColors" runat="server"></asp:Panel>    </form></body>

NOTE:如果將頁面命名為了 Color.aspx,那么需要在代碼后置文件中修改類名,比如改成:Reflection_Color,同時頁面頂部也需要修改成Inherits="Reflection_Color",不然會出現命名沖突的問題。

下一步的思路是這樣的:我們在phColors中添加一系列的div,這些div也就是頁面上我們將要顯示的色塊。我們設置div的文本為 顏色的名稱 和 RGB數值,它的背景色我們設為相應的顏色(色塊的其他樣式,比如寬、邊框、寬度已經在head中定義)。我們知道在Asp.Net中,并沒有一個Div控件,只有HtmlGenericControl,此時,我們最好定義一個Div讓它繼承自HtmlGenericControl。

public class Div:HtmlGenericControl{    private string name;        public Div(Color c)       : base("div")    // 調用基類構造函數,創建一個 Div    {       this.name = c.Name;      // 顏色名稱              // 設置文本       this.InnerHtml = String.Format("{0}<br />RGB({1},{2},{3})", name, c.R, c.G, c.B);       int total = c.R + c.G + c.B;       if (total <= 255)     // 如果底色太暗,前景色改為明色調           this.Style.Add("color", "#eee");       // 設置背景顏色       this.Style.Add("background",String.Format("rgb({0},{1},{2})", c.R, c.G, c.B));    }}

如同我們前面所描述的,這個Div接受一個Color類型作為構造函數的參數,然后在構造函數中,先設置了它的文本為 顏色名稱 和 顏色的各個數值(通過Color結構的R, G, B屬性獲得)。然后設置了div的背景色為相應的RGB顏色。

NOTE:在上面 if(total<=255)那里,可能有的顏色本身就很暗,如果這種情況再使用黑色的前景色那么文字會看不清楚,所以我添加了判斷,如果背景太暗,就將前景色調的明亮一點。

OK,現在我們到后置代碼中只要做一點點的工作就可以了:

protected void Page_Load(object sender, EventArgs e){    List<Div> list = new List<Div>();    Type t = typeof(Color);      // 頁首已經包含了 using System.Drawing;    // 獲取屬性    PropertyInfo[] properties = t.GetProperties(BindingFlags.Static | BindingFlags.Public);    Div div;    // 遍歷屬性    foreach (PropertyInfo p in properties)    {       // 動態獲得屬性       Color c;                 c = (Color)t.InvokeMember(p.Name, BindingFlags.GetProperty, null, typeof(Color), null);                      div = newDiv(c);       list.Add(div);    }    foreach (Div item in list)   {       pnColors.Controls.Add(item);    }}

上面的代碼是很直白的:先創建一個Div列表,用于保存即將創建的色塊。然后獲取Color類型的Type實例。接著我們使用GetProperties()方法,并指定BindingFlags獲取所有的靜態公共屬性。然后遍歷屬性,并使用InvokeMember()方法獲取了屬性值,因為返回的是一個Object類型,所以我們需要把它強制轉換成一個Color類型。注意在這里InvokeMember的BindingFlags指定為GetProperty,意為獲取屬性值。第四個參數為typeof(Color),因為顏色屬性(比如DarkGreen)是靜態的,不是針對于某個實例的,如果是實例,則需要傳遞調用此屬性的類型實例。最后,我們根據顏色創建div,并將它加入列表,遍歷列表并逐一加入到Id為pnColors的Panal控件中。

現在已經OK了,如果打開頁面,應該可以看到類似這樣的效果:

為列表排序

上面的頁面看上去會比較亂,因為列表大致是按顏色名稱排序的(Transparnet例外),我們最好可以讓列表基于顏色進行排序。關于列表排序,我在 基于業務對象的排序 一文中已經非常詳細地進行了討論,所以這里我僅給出實現過程,而不再進行講述。這一小節與反射無關,如果你對排序已經非常熟悉,可以跳過。

在頁面上添加一個RadioButtonList控件,將AutoPostBack設為true,我們要求可以按名稱和顏色值兩種方式進行排序:

排序:<asp:RadioButtonList ID="rblSort" runat="server" AutoPostBack="true" RepeatDirection="Horizontal" RepeatLayout="Flow">    <asp:ListItem Selected="True">Name</asp:ListItem>     <asp:ListItem>Color</asp:ListItem>        </asp:RadioButtonList>

在后置代碼中,添加一個枚舉作為排序的依據:

public enum SortBy{    Name,         // 按名稱排序    Color         // 暗顏色值排序}

修改Div類,添加 ColorValue字段,這個字段代表顏色的值,并創建嵌套類型ColorComparer,以及方法GetComparer:

public class Div:HtmlGenericControl{    private int colorValue;    private string name;        public Div(Color c)       : base("div")    // 調用基類構造函數,創建一個 Div    {       this.name = c.Name;      // 顏色名稱       this.colorValue =        // 顏色的色彩值           c.R * 256 * 256 + c.G * 256 + c.B;              // 設置文本       this.InnerHtml = String.Format("{0}<br />RGB({1},{2},{3})", name, c.R, c.G, c.B);       int total = c.R + c.G + c.B;       if (total <= 255)     // 如果底色太暗,前景色改為明色調           this.Style.Add("color", "#eee");       // 設置背景顏色       this.Style.Add("background",String.Format("rgb({0},{1},{2})", c.R, c.G, c.B));    }        // 返回一個Comparer()用于排序    public static ColorComparer GetComparer(SortBy sort) {       return new ColorComparer(sort);    }    // 默認以名稱排序    public static ColorComparer GetComparer() {       return GetComparer(SortBy.Name);    }        // 嵌套類型,用于排序    public class ColorComparer : IComparer<Div>    {       private SortBy sort;       public ColorComparer(SortBy sort) {           this.sort = sort;       }       // 實現IComparer<T>接口,根據sort判斷以何為依據一進排序       public int Compare(Div x, Div y)       {           if (sort == SortBy.Name)              return String.Compare(x.name, y.name);           else              return x.colorValue.CompareTo(y.colorValue);       }    }}

在Page_Load事件上面,我們添加語句,獲取當前的排序依據(枚舉):

SortBy sort;if (!IsPostBack) {    sort = SortBy.Name;} else {    sort = (SortBy)Enum.Parse(typeof(SortBy), rblSort.SelectedValue);}

在將列表輸出到頁面之前,我們調用列表的Sort方法:

list.Sort(Div.GetComparer(sort));   // 對列表進行排序foreach (Div item in list)   {    pnColors.Controls.Add(item);}

好了,所有工作都完成了,再次打開頁面,可以看到類似如下畫面,我們可以按照名稱或者顏色值來對列表進行排序顯示:

總結

本文分三個部分講述了.Net中反射的一個應用:動態創建對象和調用對象方法(屬性、字段)。我們先學習最常見的動態創建對象的兩種方式,隨后分別討論了使用Type.InvokeMember()和MethodInfo.Invoke()方法來調用類型的實例方法和靜態方法。最后,我們使用反射遍歷了System.Drawing.Color結構,并輸出了顏色值。

感謝閱讀,希望這篇文章能給你帶來幫助!

轉自:http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产在线一区二区三区| 精品在线欧美视频| 亚洲欧美日韩区| 538国产精品视频一区二区| 亚洲人成人99网站| 国产在线视频不卡| 亚洲最大av网| 欧美午夜女人视频在线| 国产成人精品久久亚洲高清不卡| 亚洲精品资源美女情侣酒店| 日韩在线中文字幕| 国产精品一区二区三区久久| 国产精品视频久久久久| 在线亚洲国产精品网| 精品久久久久久久久久| 欧美区在线播放| 国产精品亚洲自拍| 国内揄拍国内精品| 91久久精品国产91久久性色| 国产九九精品视频| 成人在线观看视频网站| 中文字幕欧美日韩在线| 国产精品激情av电影在线观看| 18久久久久久| 欧美亚州一区二区三区| 国产69精品久久久| 麻豆国产va免费精品高清在线| 欧美孕妇孕交黑巨大网站| 日韩欧美中文免费| 黑人精品xxx一区| 亚洲xxx大片| 久久99亚洲热视| 久久99视频免费| 国产精品日韩专区| 亚洲精品视频免费| 奇米四色中文综合久久| 欧美在线一级va免费观看| 中文欧美日本在线资源| 欧美精品一区二区免费| 日韩男女性生活视频| 日韩精品极品毛片系列视频| 日韩欧美有码在线| 夜夜躁日日躁狠狠久久88av| 国产精品视频自在线| 日韩高清av一区二区三区| 亚洲精品电影网站| 欧美人交a欧美精品| 91po在线观看91精品国产性色| 欧美性猛交xxxx免费看久久久| 国产精品扒开腿做爽爽爽的视频| 久久久欧美一区二区| 午夜精品美女自拍福到在线| 亚洲精品国产精品国产自| 欧美日韩国产限制| 欧美激情一区二区三区久久久| 国产精品久久久久久av下载红粉| 自拍偷拍亚洲区| 中文字幕亚洲色图| 精品国产乱码久久久久久婷婷| 日本成人免费在线| 欧美黑人巨大精品一区二区| 日韩精品亚洲视频| 国产精品入口免费视| 国产一级揄自揄精品视频| 亚洲国产中文字幕久久网| 欧美巨乳在线观看| 亚洲国产中文字幕久久网| 精品福利一区二区| 国产区精品在线观看| 欧美精品激情视频| 国产999在线观看| 欧美老肥婆性猛交视频| 久久激情视频免费观看| 亚洲精品美女视频| 国产亚洲精品日韩| 国产国产精品人在线视| 91久久久久久久久久久| 成人激情综合网| 91在线观看免费网站| 欧美日韩国产成人在线观看| 日本精品va在线观看| 91午夜在线播放| 色综合老司机第九色激情| 欧美精品18videos性欧| 国产精品一区二区三| 国产精品久久久久999| 亚洲视频在线视频| 欧美极品欧美精品欧美视频| 红桃视频成人在线观看| 久久久影视精品| 51精品在线观看| 国语自产精品视频在线看一大j8| 最近2019年日本中文免费字幕| 欧美一级在线亚洲天堂| 97在线精品视频| 欧美精品日韩www.p站| 国产精品va在线播放我和闺蜜| 亚洲国产精品久久久久秋霞蜜臀| 久久免费视频网| 精品久久久久久久久中文字幕| 日韩av在线直播| 亚洲视频在线观看| 国产日韩欧美夫妻视频在线观看| 2019国产精品自在线拍国产不卡| 高清视频欧美一级| 日韩av在线天堂网| 97超碰色婷婷| 91精品国产高清久久久久久| 日韩美女写真福利在线观看| 97视频在线观看免费高清完整版在线观看| 91欧美精品成人综合在线观看| 精品久久久久久久中文字幕| 国产日产欧美精品| 在线视频日韩精品| 国产成人亚洲综合青青| 欧美成人sm免费视频| 日本欧美在线视频| 亚洲成色777777女色窝| 美女精品视频一区| 欧美成人三级视频网站| 国产亚洲一级高清| 亚洲护士老师的毛茸茸最新章节| 黄网动漫久久久| 色老头一区二区三区在线观看| 大胆欧美人体视频| 亚洲精品一区二区网址| 一区三区二区视频| 久久久精品网站| 成人欧美一区二区三区在线湿哒哒| 国产99久久久欧美黑人| 日韩黄色高清视频| 91在线观看免费高清完整版在线观看| 91精品国产综合久久香蕉的用户体验| 亚洲国产美女久久久久| 亚洲国产精品久久精品怡红院| 欧美成人精品激情在线观看| 国模精品一区二区三区色天香| 国产一区二区三区毛片| 日韩精品欧美国产精品忘忧草| 亚洲人成在线观看网站高清| 午夜美女久久久久爽久久| 欧美高清视频一区二区| 亚洲电影免费观看| 午夜精品久久久久久久白皮肤| 国产精品第100页| 亚洲综合精品一区二区| 91久久久久久久一区二区| 亚洲最大av网| 97视频网站入口| 亚洲美女视频网站| 在线电影欧美日韩一区二区私密| 久久久噜噜噜久噜久久| 色综合视频一区中文字幕| 国产精品久久久久久久久久小说| 日韩中文字幕网站| 亚洲男人的天堂在线| 国产精品久久久久久婷婷天堂| 久久69精品久久久久久国产越南| 一区二区在线视频| 91精品视频在线免费观看| 亚洲国产精品女人久久久| 精品在线欧美视频| 亚洲性xxxx| 日韩av大片免费看|