Today I refactored some code that has been bugging me for a while, and wanted to share the results. The change resulted in a substantial code reduction and what I felt was a more elegant solution.
The code that I was looking at had a whole suite of objects that all implemented a proprietary ITransactionHandler interface, with methods such as Process(), and properties such as TransactionType and TransactionName. It was the latter two that made for some very verbose and awkward code. I found this basic pattern repeated in each class, and there were some 40 of these:
public class Tran114 : BaseTransactionHandler { #region Properties #region TransactionName public override string TransactionName { get { return "Commodity Receipt (Detail)"; } } #endregion TransactionName #region TransactionType public override int TransactionType { get { return 114; } } #endregion TransactionType #endregion Properties // ... }
Basically, each subclass of BaseTransactionHandler needed to be tagged with it's TransactionType and it's TransactionName.
Custom attributes to the rescue!
Instead, I implemented a custom attribute class (note the use of automatic properties, this is not required for custom attributes but saves some typing):
using System; [AttributeUsage(AttributeTargets.Class)] public class HJTransactionAttribute : Attribute { public HJTransactionAttribute(string transactionName, int transactionType) { this.TransactionName = transactionName; this.TransactionType = transactionType; } public int TransactionType { get; set; } public String TransactionName { get; set; } }
Now, I tagged each class with this new attribute, for instance:
[HJTransactionAttribute("Commodity Receipt (Detail)", 114)] public class Tran114 : BaseTransactionHandler { // .. }
The code that used to rely on the objects implementing ITransactionHandler to access the TransactionType and TransactionName parameters changed to use these helpers that extract the attribute values from a handler instance in runtime:
public static HJTransactionAttribute GetHJTransactionAttribute(object handler) { object[] attrs = handler.GetType().GetCustomAttributes(typeof(HJTransactionAttribute), false); if (attrs.Length == 1) return attrs[0] as HJTransactionAttribute; else throw new VelocityOperationalError("Transaction Handler does not have HJTransactionAttribute"); } public static int GetTransactionType(object handler) { return GetHJTransactionAttribute(handler).TransactionType; } public static string GetTransactionName(object handler) { return GetHJTransactionAttribute(handler).TransactionName; }
For instance:
private static void ReportError(WMS_ImportQueue record, ITransactionHandler handler) { // ... info.Add("handler name", HJTransactionMgr.GetTransactionName(handler)); info.Add("handler tran type", HJTransactionMgr.GetTransactionType(handler).ToString()); // .. }
You can read more about custom attributes here.
Remember Me
a@href@title, i, strike, u
Copyright © 2003-2008 Falafel Software Inc.
Subscribe to Falafel Blogs
The opinions expressed herein are Falafel's employees own personal opinions and do not represent Falafel Software's view in any way in case they go bananas!