Wednesday, August 20, 2008

Looping through Constants and other Fields

In a project I inherited I noticed that the previous Developer made heavy use of Constants and tended to do some rather laborious if/then conditional checks related to these Constants.

Here is the pattern of code used:


if (MethodToCheckIfNeeded(Class.Constant))
return (MethodToDoAction(Class.Constant);

NOTE: You would replace "Class" with the defining class/type and "Constant" to the specific Constant value you are inspecting

The idea is that the IF condition runs a "check" based on the value of the Constant to determine if action is needed. If action is indeed necessary then the code runs the associated "action" method sending in the same Constant value as the parameter.

This is not only laborious but it means that for every new Constant of the "type" being checked you have to go add corresponding if/then checks everywhere to handle this new data.

The really bad part is that this same conditional check is done several times based on the same Constant values. The previous Developer just kept doing that over and over again. You would have thought he would have seen a "pattern" there.

This Developer also tended to prefix Constant Variables with a "type" such as PARAM, FLD or TBL. With this in mind, we can easily loop through the "fields" of the class to either make a list or initiate an action on a given Constant.

Here is a solution that can easily be re-used:

// Define the Constant Values to be used
public const string PARAM_ONE = "This";
public const string PARAM_TWO = "is";
public const string PARAM_THREE = "a";
public const string PARAM_FOUR = "better";
public const string PARAM_FIVE = "solution";


...


FieldInfo[] fieldInfo = this.GetType().GetFields();

string constantValues = string.Empty;

foreach (FieldInfo fi in fieldInfo)
{
// We are only looking for Constants
if (fi.IsLiteral)
{
if (fi.Name.Substring(0, 6) == "PARAM_")
constantValues += fi.GetValue(fi) + " ";

}

}

if (constantValues != string.Empty)
MessageBox.Show(constantValues);



Notice in the sample above that I am checking only for Constants that have a prefix of "PARAM_".

Also notice that I am limiting my check down to "literals" which means they are values that are defined at runtime and not changed (i.e. Constants).

There are other checks you can do there as well.

Another thing to note is that the GetFields() method also provides for further filtering using BindingFlags such as Public, Static, etc. In this case my Constants are Public and that is the default for GetFields().

Just to illustrate the technique, I am concatenating the values of the "PARAM" Constants into a single String and Displaying the "message" via a MessageBox.

In the case of the problem I am trying to solve, in the loop I could call the "IsNeeded" method using the Constant's Value and in the "then" part of the condition I could call the "Action" method with that same value.

You could further create a List of these values that could be re-used in other methods so that you don't have to re-run this code again to retrieve the values but either way you still have to do a loop to get the job done.

Clean, simple and I don't have to keep adding new if/then code every time I add new Constants of a given "type".

I like it :)

I'm sure there are other solutions so if anyone would care to share please do.

No comments: