當必須使用反射時,自訂屬性可大幅降低執行期錯誤風險,將「發現目標」的責任從命名慣例轉移給編譯器與屬性系統。
需求:啟動時掃描 Addins 目錄組件,自動發現並安裝選單命令處理器。
[AttributeUsage(AttributeTargets.Class)]
public class CommandHandlerAttribute : Attribute { }
string addInsDir = Path.Combine(Application.StartupPath, "Addins");
foreach (string dll in Directory.GetFiles(addInsDir, "*.dll")) {
Assembly asm = Assembly.LoadFrom(dll);
foreach (Type t in asm.GetExportedTypes()) {
if (t.GetCustomAttributes(typeof(CommandHandlerAttribute), false).Length > 0) {
// 找到處理器類別,建立實例...
}
}
}
[AttributeUsage(AttributeTargets.Property)]
public class DynamicMenuAttribute : Attribute {
public string MenuText { get; set; }
public string ParentText { get; set; }
public DynamicMenuAttribute(string cmd, string parent) { MenuText = cmd; ParentText = parent; }
}
object handlerInstance = Activator.CreateInstance(t);
foreach (PropertyInfo p in t.GetProperties()) {
var attrs = p.GetCustomAttributes(typeof(DynamicMenuAttribute), false);
foreach (Attribute at in attrs) {
var dym = at as DynamicMenuAttribute;
if (dym != null) {
var mi = p.GetGetMethod();
var eh = mi.Invoke(handlerInstance, null) as EventHandler;
UpdateMenu(dym.ParentText, dym.MenuText, eh);
}
}
}
[CommandHandler]
public class CmdHandler {
[DynamicMenu("Test Command", "Parent Menu")]
public EventHandler CmdFunc {
get {
if (_handler == null) _handler = new EventHandler(DynamicCommandHandler);
return _handler;
}
}
private void DynamicCommandHandler(object sender, EventArgs e) { /* ... */ }
}
AttributeTargets);屬性與反射結合,能建立類型安全、易擴展的動態系統。設計屬性類別、限制適用範圍、封裝發現邏輯,是開發外掛架構、工具框架的關鍵技巧。