任何程式設計語言的任何特點都是有存在的道理的,C#中有些特點也許我們不求甚解的用過,但是如果知道它的使用背景與原理,使用起來將更加得心應手。本文主要分析的就是C#中的類型反射、晚期綁定、特性編程。闡釋為什麼要用這些語言特點?
首先看一下簡單項目的需求:程式員開發了很多模組,每個模組對應相應的功能,不同的使用者可能需要使用的模組不一樣,模組以外掛程式的形式與系統整合,也就是提供給使用者一個自訂模組的功能。
更加形象的比如:一個通用的圖書館裡系統中有普通老師模組、有院長模組、有校長模組、有學生模組,這些模組都具有借書的功能(每個模組借書本數不一樣);這個通用的系統可能給很多學校使用,每個學校根據自己的需求選擇模組。
對於上面這個需求分析,1、由於這些模組都具有借書的功能,首先想到的是建立一個介面,介面中包含一個借書的函數,所有模組都要實現這個介面。
2、分別實現這些外掛程式模組,編譯成程式集DLL檔案。
3、由於這是一個通用的系統,模組的選擇應該由使用者決定,因此我們不能預先把所有的模組功能都編譯到系統中去(晚期綁定派上用場)。
4、使用者選擇一個模組(DLL檔案),就相當於要載入一個程式集DLL(動態載入的概念),此時的DLL與用C/C++編寫的DLL不一樣,它是由微軟中繼語言IL組成的,裡面記錄了
DLL所有資訊的中繼資料。
5、需要調用具體某個DLL模組中的具體借書函數,這個時候就需要從動態載入的DLL中擷取到相應的類,執行個體化類,調用類的成員函數,這個就需要反射來幹了。
6、有的時候在大型項目中,每個模組可能有不同的子部門來做,因此每個模組應該包好有這些部門的基本資料,這個時候在編寫模組的功能時候,就可利用C#中的特性編程了,利用特性可以
給模組附加上額外的資訊,這些資訊會被編譯到程式集中,同理我們也可以反射出這些資訊來。
下面是一個簡單代碼的例子:利用了這些特性
外掛程式介面的定義:
View Code
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CommonTypes{ //定義一個介面 public interface IAppDll { void DoThing(); } //自訂屬性類別 [AttributeUsage(AttributeTargets.Class)] public sealed class CarInfoAttribute : System.Attribute { public string name{ get; set;} }}
根據上面的定義的介面約束,開發第三方的外掛程式
View Code
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using CommonTypes;namespace CsharpDll{ [CarInfo(name="這是第三方生產的外掛程式")] public class CsharpModule:IAppDll { public void DoThing()//實現介面中的函數 { MessageBox.Show("正在調用的是Csharp外掛程式模組"); } }}
在表單程式中調用第三方外掛程式
View Code
using System;using System.Collections.Generic;using System.ComponentModel;using System.Data;using System.Drawing;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows.Forms;using System.Reflection;using CommonTypes;namespace WindowsFormsApplication1{ public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void openToolStripMenuItem_Click(object sender, EventArgs e) { //選擇一個外掛程式載入 OpenFileDialog OFD = new OpenFileDialog(); if (OFD.ShowDialog() == DialogResult.OK) { if (!LoadModule(OFD.FileName)) MessageBox.Show("沒有成功載入第三方的外掛程式!"); } } private bool LoadModule(string path) { bool FindModule = false; Assembly asm = null; try { //載入指定路徑下的程式集 asm = Assembly.LoadFrom(path); } catch (Exception ex) { MessageBox.Show(ex.Message); return FindModule; } //得到程式集中所有的IAppDll介面相容的累 var ClassTypes = from t in asm.GetTypes() where t.IsClass && (t.GetInterface("IAppDll") != null) select t; //建立對象,並調用類中的方法 foreach (Type t in ClassTypes) { FindModule = true; //使用晚期綁定建立類型,強制轉換為介面類型 IAppDll someApp =(IAppDll)asm.CreateInstance(t.FullName, true); someApp.DoThing(); listBox1.Items.Add(t.FullName); //顯示外掛程式的相關資訊 DisplayCarinfo(t); } return FindModule; } //顯示外掛程式的資訊 private void DisplayCarinfo(Type t) { var info = from carAtr in t.GetCustomAttributes(false) where (carAtr.GetType() == typeof(CarInfoAttribute)) select carAtr; //顯示特性的屬性 foreach (CarInfoAttribute cia in info) { MessageBox.Show(cia.name); } } }}