Introduction
I was refactoring some code that was used to access AppSettings
and figured I could do it better. The ConfigurationManager.AppSettings.Get
method was being used to set a private
field, and then that value was being used to set a property, and this was basically being set in a method.
Design
I decided that it would be better to do this in a static
class, and that I could directly set the properties. However, the values had been in string
s, and needed to be converted, and the Parse
would not work on fields, even considering their disadvantage of not dealing with exceptions. I therefore started working on the idea of creating a TryParse
method that was an extension method. I only needed to deal with a few types, so even though I had to create a method for each type, it was not too much work. As an added bonus, I decided to also create a method to deal with enumerations:
public static class Converters
{
public static bool TryParseBool(this string str, bool defaultValue = false)
{
bool k;
if (bool.TryParse(str, out k)) return k;
return defaultValue;
}
public static int TryParseInt(this string str, int defaultValue = 0)
{
int k;
if (int.TryParse(str, out k)) return k;
return defaultValue;
}
public static double TryParseDouble(this string str, double defaultValue = 0)
{
double k;
if (double.TryParse(str, out k)) return k;
return defaultValue;
}
public static T TryParseEnum<T>(this string str, T defaultValue) where T : struct
{
T k;
if (Enum.TryParse<T>(str, out k)) return k;
return defaultValue;
}
}
Another option is to create a generic that uses the TypeConverter
, which means that on a single method is required as long as a TypeConverter
exists for the class
/struct
:
public static T TryParse<T>(this string text, T defaultValue = default(T))
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
return (converter?.IsValid(text) == true) ? (T)converter.ConvertFromInvariantString(text)
: defaultValue;
}
In this case would have to have the Type
to convert to in the angle brackets after the TryParse
.
The static
class that handled the appSettings
became:
public static class Constants
{
public static int DataVersion { get; } = ConfigurationManager.AppSettings
.Get("DataVersion").TryParseInt();
public static int SimulationPort { get; } = ConfigurationManager.AppSettings
.Get(nameof(SimulationPort)).TryParseInt();
public static double Value { get; } = ConfigurationManager.AppSettings
.Get(nameof(Value)).TryParse<double>();
}
Basically, one line for each of the appSettings
. Notice that on the second property I use the nameof
method instead of a string
. I prefer using the same name, but obviously if different names are used, cannot use this method. The third property uses the generic version.
History
- 03/15/2016: Initial version