Now, if you check isValidBoolean.HasValue and it returns true, you know you have a valid bool value. isValidBoolean.Value would give you the actual value after you've confirmed that you have a value. One thing though: GetValue method throws an exception if it finds a value that cannot be converted to the specified type.
Does not look too promising? Wait, there's more: Let me show you an implementation using Generics where we can get typed values from app.config, raise exceptions/log if key is not found and even return a default value if the value found is not suitable:
1: class TypedAccessor<T>
2: {
3: // typesafe AppSettingsReader supporting default values
4: T _defaultValue;
5: bool _required;
6: bool _warn;
7: string _keyName;
8: readonly AppSettingsReader _reader;
9:
10: /// <summary>
11: /// Initializes a new instance of the <see cref="TypedAccessor<T>"/> class.
12: /// </summary>
13: /// <param name="reader">The reader.</param>
14: /// <param name="keyName">Name of the key.</param>
15: /// <param name="warnIfKeyNotFound">if set to <c>true</c> [warn if key not found].</param>
16: /// <param name="isRequired">if set to <c>true</c> [is required].</param>
17: /// <param name="defaultValue">The default value.</param>
18: public TypedAccessor(AppSettingsReader reader, string keyName, bool warnIfKeyNotFound, bool isRequired, T defaultValue)
19: {
20: // An additional parameter Logger can be added to trace what is happening here
21: _defaultValue = defaultValue;
22: _required = isRequired;
23: _warn = warnIfKeyNotFound;
24: _keyName = keyName;
25: _reader = reader;
26: }
27:
28: /// <summary>
29: /// Fetches this instance.
30: /// </summary>
31: /// <returns>A value of Type T</returns>
32: public T Fetch()
33: {
34: T value;
35:
36: if (_warn && !ConfigurationManager.AppSettings.AllKeys.Contains(_keyName))
37: {
38: Console.WriteLine("The Key {0} is not present in the app.config file.", _keyName);
39: throw new ApplicationException(string.Format("The Key {0} is not present in the app.config file.", _keyName));
40: }
41:
42: try
43: {
44: value = (T)this._reader.GetValue(this._keyName, typeof(T));
45: }
46: catch (System.Exception ex)
47: {
48: if (_warn)
49: {
50: // Log in a real application
51: Console.WriteLine("Error encountered while fetching value of the Key {0}. Default value will be returned.", _keyName);
52: }
53:
54: if (_required)
55: {
56: // Log in a real application
57: Console.WriteLine("The Key {0} is required, but is not present in the app.config file", _keyName);
58: }
59:
60: value = _defaultValue;
61: }
62:
63: return value;
64: }
65: }
How does that look? Looks very promising to me!!
More ideas on making this even more useful:
1) Most (if not all) of the config values would be of a built-in datatype, so an additional check can be added to check if a value is of a built-in type E.g.
this stackoverflow discussion
2) You may want to encapsulate the logic of returning a default value to another type something like the below:
a) An enum of key names
b) A Dictionary
containing the keyname, default value
c) A method on this type to return the default value for a specified key
Happy Coding