C#中的Reflection反射(反映)用法

如果你程式碼中有要動態到動態極限的需求,那麼你會發現你根本沒有辦法動態的指定一個物件的類別。舉例來說,程式碼如「DataTable oDT = new DataTable();」,你根本沒有辦法在執行期才指定是要載入DataTable類別,也就是說一開始你注定只能夠在程式碼裡寫死了。如果你屈服於這樣的困境,那你就永遠不可能完成極致的動態了。

別灰心,Microsoft .NET Framework 2.0後提供了System.Reflection類別,就是專門要來解決這個問題,一般在我們都稱為「反射」,但是官方稱為「反映」也頗為傳神,這個功能最主要的就是可讓您取得已載入組件(Assemblies)及組件中所定義型別的相關資訊,例如類別(classes)、介面(interfaces)及實值型別(value types)等。講的更白一點,就是你可以透過「字串」的指定,就可以動態的將某物件指派成「你字串中指定要實體化的類別」並且進行操作,這簡直是太動態了。

微軟MSDN中對於Reflection的介紹。

話不多說,下面的程式碼展示出,你可以透過動態的方式,隨意的將你程式碼中的物件動態指派成某一個類別,並且進行相關的操作,包含屬性的指派,以及介面成員的方法調用等。(程式運行的環境是命令列CMD)

namespace Reflection
{
	class Program
	{
		static void Main(string[] args)
		{
			//使用者輸入
			System.Console.Write("請輸入您的交通工具類型(1.摩托車;2.汽車):");
			int iMachineType = System.Convert.ToInt32(System.Console.ReadLine());
			System.Console.Write("請輸入您的交通工具匿稱:");
			string cTargetName = System.Console.ReadLine();

			//定義等一下要調用的物件名稱
			//請注意,這邊並沒有使用「早期繫結」的方式,把物件名稱寫死在程式碼之中
			string cTargetClassName = "Reflection.Transportation";
			string cTargetProperty = "Name";
			string cTargetMethodName = "Wheels";

			System.Object oTemp = System.Activator.CreateInstance(System.Type.GetType(cTargetClassName));
			System.Type oTypeBase = System.Type.GetType(cTargetClassName);
			
			//設定與展示物件的名稱屬性
			System.Reflection.PropertyInfo oProperty = oTypeBase.GetProperty(cTargetProperty);
			oProperty.SetValue(oTemp, cTargetName);
			System.Console.Write("您的愛車{0}", oProperty.GetValue(oTemp));

			//依使用者選擇的「字串」,動態轉換物件去調用介面成員
			System.Object oEntity;
			switch (iMachineType)
			{
				case 2:
					oTypeBase = System.Type.GetType("Reflection.ICar");
					oEntity = (ICar)oTemp;
					break;
				default:
					oTypeBase = System.Type.GetType("Reflection.IBike");
					oEntity = (IBike)oTemp;
					break;
			}
			System.Reflection.MethodInfo oMethod = oTypeBase.GetMethod(cTargetMethodName);
			System.Console.WriteLine("擁有{0}顆輪子。", oMethod.Invoke(oEntity, null));

			System.Console.Read();
		}
	}

	//交通工具類別
	class Transportation : ICar, IBike
	{
		public string Name { get; set; }
		int ICar.Wheels() { return 4; }
		int IBike.Wheels() { return 2; }
	}

	//小客車介面
	interface ICar
	{
		int Wheels();
	}

	//機踏車介面
	interface IBike
	{
		int Wheels();
	}
}

運行出來的畫面如下:

通常,程式設計應該不會做到如此動態的工法,但是如果你強調要把類別模型完全解耦合,System.Reflection或許是一個很好的類別載入器。Reflection反射(反應)的撰寫過程通常會跟Attribute屬性(特性)出現在一塊,原因是因為你可能需要從某一個類別(或已經編譯好的DLL)中取出寫這個組件當時的一些資訊,然後再動態的從程式碼中決定要調用哪一個適當的類別以及方法。

對Attribute有興趣者,可以參考「C#中的Attribute屬性(特性)用法」。

C# Reflection 反射 反映 Attribute