當前位置:編程學習大全網 - 編程語言 - 有關C# 映射的詳解

有關C# 映射的詳解

我們知道,C#編譯後的PE文件主要由IL代碼和元數據組成,元數據為.NET組件提供了豐富的自描述特性,它使得我們可以在代碼運行時獲知組件中的類型等重要的信息。在C#中這是通過壹種稱作映射(Reflection)的機制來完成的。先來看壹個示例,我們首先創建壹個簡單的類型:

// SimpleType.cs

public class MyClass

{

private int count=100;

public int Count

{ get{ return count; }

set{ count=value; }

}

public void Print()

{ System.Console.WriteLine(count);}

}

用編譯命令csc /t:library SimpleType.cs編譯上面的文件得到SimpleType.dll輸出。我們再來實現查詢類型的測試程序:

//Test.cs

using System;

using System.Reflection;

class Test

{

public static void Main(string[] args)

{

Type t = typeof(MyClass);//獲取MyClass的類型信息

Console.WriteLine("The Type Name : {0}",t.Name);//獲取類型的名字

FieldInfo[] fiArr=t.GetFields();//獲取所有的***有域

Console.Write("The {0} Fields :",fiArr.Length);

foreach(FieldInfo o in fiArr)

{

Console.Write(o.Name+" ");

}

Console.WriteLine();

PropertyInfo[] piArr=t.GetProperties();//獲取所有的公有屬性

Console.Write("The {0} Properties :",piArr.Length);

foreach(PropertyInfo o in piArr)

{

Console.Write(o.Name+" ");

}

Console.WriteLine();

MethodInfo[] miArr=t.GetMethods();//獲取所有的公有方法

Console.Write("The {0} Methods :",miArr.Length);

foreach(MethodInfo o in miArr)

{

Console.Write(o.Name+" ");

}

}

}

用編譯命令csc /r:simpletype.dll test.cs編譯後,執行可得到下面的輸出:

The Type Name : MyClass

The 0 Fields :

The 1 Properties :Count

The 7 Methods :GetHashCode Equals ToString get_Count set_Count Print GetType

在上面的例子中,我們首先通過 typeof(MyClass)獲得類MyClass的類型信息,當然我們也可以通過創建對象實例,然後調用對象實例的GetType方法來獲得(每個類都從object根類中繼承獲得此方法)。在擁有了類型信息(變量t)後,我們便可以獲得其類型的名字,該類型含有的公有域,公有屬性,公有方法。註意這裏C#的映射機制只允許我們獲取類型的公有信息,這符合面向對象的封裝的原則。這也是為什麽我們雖然我們實現了count域,查詢類型得到的輸出卻是“The 0 Fields :”——如果將SimpleType.cs中的count域改為public公有,我們將會得到他的查詢信息。其中4個方法(GetHashCode Equals ToString GetType)都是繼承自object類的公有方法,而方法get_Count 和set_Count則是我們在實現Count屬性的“副產物”——這符合我們前面講述的屬性本質上為方法的變體。實際上,System.Type類各種各樣的成員使得我們能夠獲得幾乎所有的與類型相關的公有信息。在System.Reflection命名空間下的各個類更是可以獲得各個編程元素更較詳細的信息,如方法的參數與返回值,域的類型,枚舉的各個值等。

動態創建與調用

實際上映射還遠遠不止於動態地獲知組件的類型信息,它還能使我們在獲得類型信息的基礎上,在代碼運行時進行類型的動態創建與方法的動態調用,甚至於動態地創建並執行IL代碼!

動態調用為C#的組件提供了晚綁定功能,它使得組件之間在運行時的集成變得極為方便!利用前面創建的簡單的組件SimpleType.dll,我們來看壹看怎樣完成對象的動態創建和方法的動態調用:

// DynamicExe.cs

using System;

using System.Reflection;

class Test

{

public static void Main()

{

Assembly a=Assembly.LoadFrom("SimpleType.dll");//裝載組件

foreach(Type t in a.GetTypes())

{

if(t.IsClass && !t.IsAbstract)

{

MethodInfo[] miArr=t.GetMethods();//獲得類型的公有方法

object o=Activator.CreateInstance(t);//創建實例(無參構造器)

foreach(MethodInfo mi in miArr)

{

if(!mi.IsAbstract && !mi.IsStatic

&& mi.GetParameters().Length==0)

{

object re=mi.Invoke(o,null);//調用實例方法

Console.WriteLine("{0} , Return :{1}",mi.Name,re);

}

}

}

}

}

}

用編譯命令csc /r:simpletype.dll dynamicexe.cs編譯後,執行可得到下面的輸出:

GetHashCode , Return :8

ToString , Return :MyClass

get_Count , Return :100

100

Print , Return :

GetType , Return :MyClass

我們在上面的例子給出了被動態調用的方法的名字和返回值。其中輸出的第4行為100,它是我們動態調用方法MyClass.Print() 的輸出。需要指出的是我們通過壹定的控制,僅僅調用的是類型的公有的無參數的實例方法。給出組件的名字,運用Assembly.LoadFrom我們便可以動態的裝載組件。Activator.CreateInstance允許動態地創建類型(我們這裏只通過無參的構造器來創建),實際上用它創建出來的類型和我們用MyClass o=new MyClass()創建出來的類型壹模壹樣。進而,我們便可以在查詢到的成員的基礎上,對它們進行動態調用。

Microsoft.NET從底層的元數據設計入手,為映射機制提供了非常堅實的基礎。命名空間System.Reflection和System.Reflection.Emit為操作這種映射提供了實實在在的強大的API編程接口,大大改善了組件的設計環境,提高了組件的交互能力!

  • 上一篇:遊戲《我的世界》裏的旅遊勝地有許多是真實存在的,都有哪些?
  • 下一篇:uoc是什麽意思
  • copyright 2024編程學習大全網