Introduction
Many times in your DotNet coding, you will need to convert or test a variable to determine whether it is of some "type" (e.g.: is myVar
an integer?) And sometimes if your variable in question is null
or not the type you are expecting, you might want to default to some predefined value (e.g.: is myVar
an integer, no? Then assign -1
.) This article addresses that functionality via a helper class called DataParser
.
Without a helper class, we might see code like the following:
int myDefaultValue = -1;
object inputData = myVarToTest;
int def = myDefaultValue;
int myEndResult = myDefaultValue;
try
{
if (null == inputData) return def;
if (Int32.TryParse(inputData.ToString(), out result))
{
return result;
}
else
{
return def;
}
}
catch
{
return def;
}
Or we might see the try/catch used as the only determination of defaulting. Using the try/catch may not be the best option due to performance issues. But I'll leave that debate up to the performance gurus.
int myDefaultValue = -1;
string myVarToTest = "twenty";
int myEndResult = myDefaultValue;
try
{
myEndResult = Convert.ToInt32(myVarToTest);
}
catch
{
myEndResult = myDefaultValue;
}
return myEndResult;
Generally I dislike writing the same code blocks twice. Worse, in the case of testing request parameters on each aspx page, I might have written those blocks for multiple web pages in my app, multiplied per request parameter passed to each page. For example, the variables "userId
", "categoryId
", "subcategoryId
", "sessionId
" passed across 10 pages, could equate to 40 code blocks if not more. Blah! Code duplication and boring work.
Of course, my example is purely to communicate the basic issue, and, yes, there are a million ways to skin that cat with refactoring, etc.
So I have developed a DataParser
"helper", which helps in type conversions and defaults when needed, encapsulating the logic surrounding these functions.
In a future article, I will demonstrate how to wrap the DataParser
helper in a request parameter type parser class to locate and handle those pesky request parameters (aspx) and convert them with ease.
Using the code
The DataParser (for the most part) assumes that a variable being passed is a DotNet Object. From the Object type, the code will start determining whether our "object" is of the type you are interested in returning.
public static class DataParser
{
public static string GetStringParameter(object inputData)
{
return Convert.ToString(inputData);
}
public static string GetStringParameter(object inputData, string def)
{
try
{
if(null == inputData)
{
return def;
}
if((string)inputData == string.Empty)
{
return def;
}
return GetStringParameter(inputData);
}
catch
{
return def;
}
}
}
... and so on (download the code for a full example)
The GetStringParameter
(object <code>inputData
, string def
) excepts the "object" you want to convert to a string and a default (def) string value to use in the case where your object turns out to not be what you want (e.g. NULL
or String.Empty
).
I created two signatures, one with a default option and the other without. The signature without a default option will error if a problem occurs. This is useful if you need to control the ability to test for failure or throw the Exception within your code.
Note: the way in which the code is "determining" and "defaulting" is not necessarily the main point here – I am presenting one of many approaches. The core concept is to encapsulate "how" you think this should be done, put it in a library, use the library, and reduce code duplication (i.e. write it once and reuse it often.)
So at this point, I could call the code such as the following (NUnit) test.
[Test]
public void ParseString1_woDefault_wString()
{
string input1 = "string";
string output1 = DataParser.GetStringParameter(input1);
Assert.AreEqual(output1, input1);
}
Or an example where we send NULL to the method.
[Test]
public void ParseString1_Default_wNull()
{
string input1 = null;
string output2 = "default";
string output1 = DataParser.GetStringParameter(input1, output2);
Assert.AreEqual(output1, output2);
}
Now let's take a quick look at handling integers.
public static int GetIntParameter(object inputData)
{
return Convert.ToInt32(inputData);
}
public static int GetIntParameter(object inputData, int def)
{
int result = -1;
try
{
if(null == inputData) return def;
if(Int32.TryParse(inputData.ToString(), out result))
{
return result;
}
else
{
return def;
}
}
catch
{
return def;
}
}
These methods basically follow the same logic as the GetStringParameter()
method except that we try to determine whether our inputData
is an integer.
Again, the innards of the method (how I am determining what is an Integer) is not as important as the concept of the helper class/method. However, in this case let me emphasize that the TryParse(myValue)
technique is much faster than using a try/catch block. Google "TryParse" and "Performance" to read through some of the published metrics (or religious wars) on these two approaches. In my case, the moment I read about the TryParser()
, I updated my library and my code did run faster (e.g., unscientific test showed a huge increase when working with a large record set from how I had previously written the code.) This demonstrates my point, that by using the library class I was able to update and "better" my code across multiple pages and applications by simply editing the innards of the GetIntParameter()
method.
So at this point, we can easily test for our integer with the following line of code.
int output1 = DataParser.GetIntParameter(someUntrustedValue, -1);
That's one line of code versus our original example of ~13 lines of code. To go a step further, here's our original example, referring to the four parameters passed into an aspx page.
int myDefault = 1;
int myUserId = DataParser.GetIntParameter(userId, myDefault)
int myCategoryId = DataParser.GetIntParameter(categoryId, myDefault);
int mySubCategoryId = DataParser.GetIntParameter(subcategoryId, myDefault);
int mySessionId = DataParser.GetIntParameter(sessionId myDefault);
MyProcess(myUserId, myCategoryId, mySubCategoryId, mySessionId);
That's 7 lines of code versus a possibility of 52+ lines of code (if you didn't wise-up and write a private function in your page.) And better yet, if you find that one of your methods has an error or could be improved (e.g., performance-wise), you only have one place to change the code - which I have experienced as stated above.
Obviously this is not a new concept. But it is worth repeating and reinforcing in our teams. The amount of time you take to write the helper library will pay you back many times in the future. Of course, how to organize and decide to write and share helper libraries is another issue altogether.
The source code included with this article has the following methods.
string GetStringParameter(object inputData);
string GetStringParameter(object inputData, string def);
int GetIntParameter(object inputData);
int GetIntParameter(object inputData, int def);
double GetDoubleParameter(object inputData);
double GetDoubleParameter(object inputData, double def);
float GetFloatParameter(object inputData);
float GetFloatParameter(object inputData, float def);
long GetLongParameter(object inputData);
long GetLongParameter(object inputData, long def);
short GetShortParameter(object inputData);
short GetShortParameter(object inputData, short def);
bool GetBooleanParameter(object inputData);
bool GetBooleanParameter(object inputData, bool def);
char GetCharParameter(string name);
char GetCharParameter(string name, char def);
DateTime GetDateTimeParameter(object inputData);
DateTime GetDateTimeParameter(object inputData, DateTime def);
Guid GetGuidParameter(string guid);
Guid GetGuidParameter(object guid);
Guid GetGuidParameter(object guid, string def);
Guid GetGuidParameter(object guid, Guid def);
Guid GetGuidParameter(string guid, Guid def);
byte GetByteParameter(string name);
byte GetByteParameter(string name, byte def);
bool IsNumeric(string inputData);
History
DataParser
was originally inspired by my conversion of Java code written by Jason Hunter (the port was done years ago, and the original source is unknown.) - Version 2.0 of the
DataParser
(presented here) converted the helper to DotNet 2.0 and to a static class.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.