程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# 利用反射動態創建對象[摘錄]

C# 利用反射動態創建對象[摘錄]

編輯:C#入門知識

摘自:http://hi.baidu.com/yangyuhang/blog/item/f12ea90e13f214e336d12250.html

在VS.Net中,有很多種方法動態調用對象的構造函數。一是通過Activator類的CreateInstance()方法。這個方法我們在Remoting中也用過。它實際上是在本地或從遠程創建對象類型,或獲取對現有遠程對象的引用。它的方法簽名是:public static object CreateInstance(Type);(還有其他重載方法)注意它的返回值為object,MSDN對返回值的描述是:

二是通過Assembly類的方法CreateInstance()。方法名和前一樣,不過它不是靜態方法。Assembly是在System.Reflection命名空間中。方法簽名:public object CreateInstance(Type);(同樣還有其他重載方法)返回值仍然是object,MSDN對返回值的描述是:

當然還有其他方法,例如通過MethodInfo獲得方法信息後,根據IsConstructor屬性,判斷是否構造函數,再根據GetParamters()方法獲得參數,最後通過Invoke()方法來調用,等等……。大家可以參考MSDN。

在這裡,我且把問題簡單化,只調用其默認構造函數。通過CreateInstance()方法獲得object對象,再轉換為實際的自定義對象類型。事實證明,這種轉換為出現異常。根本的原因我還弄不清楚,初步的猜測,對於動態加載的assembly,和手動添加的assembly,Framework將兩者視為了不同的assembly,即使我們使用的是同一個DLL。

我也注意到Actovator.CreateInstance()返回的是新創建對象的引用。是否是引用再作怪呢?但Assembly.CreateInstance()方法,根據MSDN的描述,返回的是object實例,然而仍然會拋出同樣的異常。所以,出現問題的具體原因,我確實無法解釋。

確實VS.Net博大精深,很多內在的運行機制我們不得而知。好吧,我們就知其然而不知其所以然吧,至少我現在!管它這麼多,只要會用就行,退而求其次,也未嘗不可。

利用反射動態創建對象,事實上就是通過Assembly動態加載DLL。這裡所謂的“對象”,應分為兩種類型。不同的類型,解決的辦法也不相同。

一、.Net自身提供的類對象,例如Form對象、Control對象。

這也是我們在程序開發中會經常用到的。一般我們開發應用程序,都是將界面定義好。有多少個窗口,有多少個控件,事先做好,放在項目中。但有時作交互設計時,還需要考慮用戶的請求。也許用戶希望某些窗體能夠自己決定加載的時間。也就是說,需要提供運行時加載的功能。這時,就需要通過反射來動態創建對象了。(加載的窗體對象dll,通常是放在配置文件中。在.Net中,有專門的配置文件,它是xml格式。有關配置文件,我希望能專門寫一篇文章。在本文,我的例子是固定的加載程序集。) 1、創建要動態加載的窗體對象

首先,創建一個窗體對象FirstForm,這個窗體只有一個控件Lable,來顯示窗體的名稱。然後我們將它編譯為dll文件FirstForm.dll,放在e:/AutoForm中。(要生成Dll文件,而不是exe,請在Solution Explorer(解決方案資源管理器)中的 FirstForms 項目上單擊鼠標右鍵,選擇 Properties(屬性)。在 Output Type(輸出類型)組合框中選擇 Class Library(類庫)。)

這個對象的程序集名為FirstForm.dll,類型為FirstForm.Form1。

2、創建應用程序,動態加載該對象

啟動一個新的 Windows 窗體項目。將其命名為 AutoLoadForm。在新項目中包含的空窗體 Form1 中,將它的IsMdiContainer 屬性更改為 True。這樣,該窗體即變成一個 MDI 父窗體。更改窗體的大小,使窗體的長和寬的尺寸大約為默認值的兩倍。

將一個面板控件拖動到窗體上,然後設置它的 Dock 屬性,使它靠接在窗體的頂部。更改面板的大小,使它的高度大約為 50px。

將一個組合框拖動到面板上。將它命名為 cboForms,然後將它的 DropDownStyle 設置為 DropDownList

最後,將一個按鈕拖動到面板上。將它命名為 btnLoadForm,然後將它的 Text 屬性設置為 Load Form

此時,Form1 應如圖 1 所示。 

然後為程序添加命名空間: using System.Reflecton;

單擊btnLoadForm控件,寫入以下代碼:

private void btnLoadForm_Click(object sender, System.EventArgs e)
        {            
             Assembly assembly = Assembly.LoadFrom(@"e:\AutoFormFirstForm.dll");
             Type type = assembly.GetType("FirstForm.Form1");
            object obj = Activator.CreateInstance(type);
             Form formToShow = (Form)obj;
             formToShow.MdiParent = this;
             formToShow.Show();
         }

代碼說明: 1)首先是通過Assembly.LoadFrom()來加載dll文件; 2)再通過GetType()來獲得要創建的Form類對象的類型。注意,在GetType()方法的參數為類型的名字,為string類型,同時該名字應為類型的FullName,即:命名空間名.類名; 3)然後通過Activator.CreateInstance()方法創建該類型對象,返回object對象。 4)再將該對象強制轉換為Form類型。 5)最後調用即可。

運行程序,單擊按鈕,結果如下: 

結論:可以看到,對於.Net自身提供的類對象,我們對它直接強制轉換即可。不會出現任何問題。

二、自定義對象

前面已經說過,對於自定義的對象,進行強制轉換會拋出異常。因此,我們需要做些變通才行。

我們說,動態加載的Dll和手工添加的dll引用,系統會認為不是同一個Assembly。那麼應該怎麼解決?想一想,對了,應該使用接口。但是,這裡使用接口的方法稍微有點特殊。還是先按步驟來講解吧。 1、創建一個接口,該接口包括要加載對象類的方法、屬性等:

新建一個“類庫”項目,取名為AutoObjectInterface:

using System;

namespace AutoObjectInterface
{    
    public interface IAutoObject
    {
        void Print(string s);
     }        
}

這個接口很簡單,只是提供一個Print()方法而已。

然後將它編譯為Dll文件,名為AutoObjectInterface。

2、創建自定義類對象:

新建一個“類庫”項目,取名為AutoObject,添加前面創建的接口Dll引用:

using System;

namespace AutoObject
{
    public class TestObject:AutoObjectInterface.IAutoObject
    {        
        public TestObject()
        {
            
         }

        public void Print(string s)
        {
             Console.WriteLine(s);
         }
     }
}

這個類實現了第一步創建的接口。注意,這裡實現的接口不是直接寫在該類中,而是獨立的Dll。在這個類中,是添加了該接口的dll,然後再實現它。這就是前面說的使用接口的一點特殊性。

 

Obj = (AutoObjectInterface.IAutoObject)obj;

using System;
using System.Reflection;


namespace studyReflection
{    
    class Class1
    {
        
        // 應用程序的主入口點。        
         [STAThread]
        static void Main(string[] args)
        {
             Assembly assembly = Assembly.LoadFrom(@"e:NewObjectAutoObject.dll");
             Type type = assembly.GetType("AutoObject.TestObject");

            object obj = Activator.CreateInstance(type);
             AutoObjectInterface.IAutoObject iObj = (AutoObjectInterface.IAutoObject)obj;

             iObj.Print("wayfarer");
            
             Console.ReadLine();
         }
     }
}

說明:這個代碼和前面創建.Net自身提供的對象差不多,關鍵的區別就是強制轉換。因為是自定義對象,所以我們不知道轉換為什麼對象啊,所以要添加接口的引用。轉換的時候就轉換為接口的類型:

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