在 .NET Framework 推出之前,撰寫組件(Component)被視為需要高深技術的工作,讓許多開發者望而卻步。.NET 的出現徹底改變了這一局面,使組件開發變得平易近人。而作為 .NET Framework 的核心語言,C# 更被譽為「面向組件的語言」。本文將帶領您逐步了解如何使用 C# 編寫在 .NET Framework 環境下運行的組件,涵蓋組件類別的撰寫、欄位/屬性/事件的添加、異常處理,以及編譯與發布的完整流程。
我們從一個簡單的範例開始,逐步將其擴充為功能完整的組件:
using System;
namespace ComponentCS
{
public class StringComponent
{
private string[] StringsSet;
public int StringLength
{
get { return StringsSet.Length; }
}
public void Modify(int index, string value)
{
if ((index < 0) || (index >= StringsSet.Length))
throw new IndexOutOfRangeException();
else
{
StringsSet[index] = value;
OnModify();
}
}
public StringComponent()
{
StringsSet = new string[]
{
"C# String 0",
"C# String 1",
"C# String 2",
"C# String 3"
};
}
public string GetString(int index)
{
if ((index < 0) || (index >= StringsSet.Length))
throw new IndexOutOfRangeException();
return StringsSet[index];
}
}
}
首先建立命名空間來封裝組件中的類別群組。命名空間支援巢狀結構,也可將類別分散在多個檔案中:
namespace NestIt
{
namespace NestedNameSpace
{
class myClass
{
public static void DoSth() { ... }
}
}
}
引用方式:NestIt.NestedNameSpace.myClass.DoSth();
欄位直接儲存資料,屬性則透過 get/set 存取子實現封裝:
set:唯寫屬性get:唯讀屬性(如上例 StringLength)關鍵差異:屬性不能像變數般直接使用,也無法作為 ref/out 參數傳遞,這正是封裝性的體現。
建構函數與類別同名、無回傳型別、可多載。實例化時自動執行,C# 的垃圾收集機制會接管生命週期,適時回收資源。
組件必須具備完善的異常處理。雖消耗少量資源,但能大幅提升安全性。範例使用系統內建 IndexOutOfRangeException,實務上建議自訂異常類別:
public class MyApplicationException : ApplicationException
{
public string AMsg;
public MyApplicationException(string strMsg) { AMsg = strMsg; }
}
自訂異常類別需繼承 System.Exception,微軟建議繼承 ApplicationException。改寫後的 GetString 展示多層捕捉:
public string GetString(int index)
{
try
{
if ((index < 0) || (index >= StringsSet.Length))
throw new MyApplicationException("參數超出範圍");
}
catch (MyApplicationException mErr)
{
Console.WriteLine(mErr.AMsg);
}
catch (Exception Err)
{
Console.WriteLine(Err.Message);
}
return StringsSet[index];
}
事件機制讓開發更具彈性。以 event 關鍵字定義:
public event EventHandler Modified;
搭配觸發方法 OnModify:
private void OnModify()
{
EventArgs e = new EventArgs();
if (Modified != null)
Modified(this, e);
}
用戶端訂閱事件:
StringComponent mysc = new StringComponent();
mysc.Modified += new EventHandler(Called);
mysc.Modify(2, "another string");
public void Called(object o, EventArgs e)
{
Console.WriteLine("Changed");
}
使用 += 訂閱,-= 取消訂閱。
using System;
namespace ComponentCS
{
public class StringComponent
{
private string[] StringsSet;
public event EventHandler Modified;
public int StringLength
{
get { return StringsSet.Length; }
}
public void Modify(int index, string value)
{
if ((index < 0) || (index >= StringsSet.Length))
throw new IndexOutOfRangeException();
else
{
StringsSet[index] = value;
OnModify();
}
}
private void OnModify()
{
EventArgs e = new EventArgs();
if (Modified != null)
Modified(this, e);
}
public StringComponent()
{
StringsSet = new string[]
{
"C# String 0",
"C# String 1",
"C# String 2",
"C# String 3"
};
}
public string GetString(int index)
{
if ((index < 0) || (index >= StringsSet.Length))
throw new IndexOutOfRangeException();
return StringsSet[index];
}
}
}
將原始碼編譯為動態連結庫(.dll)可加速執行並保護原始碼:
csc.exe /t:library /debug+ /out:myCom.dll example.cs
參數說明:
/t:library:輸出為程式庫(DLL)/debug+:包含偵錯資訊/out:myCom.dll:指定輸出檔名十分鐘內完成一個「麻雀雖小,五臟俱全」的基礎組件。實務專案中仍需考慮版本控制、安全性、文件化等進階議題,但 C# 對組件開發的強力支援,讓開發者能將更多精力投入演算法設計與核心邏輯,打造更優質的組件。