The helper should be able to set a default value if the value can't be fetched with the provided key. There is also a bool that will throw an error if the key value or the default value could not be fetched or converted.
Can I make it more compact, safer, and still have the same functionality?
It feels like I am using too many try/catch blocks.
using System;
using System.Configuration;
namespace Successful.Misc
{
public static class AppSettingsHelper
{
private static bool ThrowException { get; set; }
private static object DefaultValue { get; set; }
public static TResult Get<TResult>(string key, Func<TResult> defaultValue = null, bool throwException = false)
{
ThrowException = throwException;
DefaultValue = defaultValue;
var result = default(TResult);
var valueOfKey = ConfigurationManager.AppSettings[key];
if (string.IsNullOrWhiteSpace(valueOfKey))
{
if (ThrowException && DefaultValue == null)
{
throw new ArgumentNullException(valueOfKey,
$"Failed to get a value for the key {key} in the App.config file.");
}
result = GetDefaultValue(defaultValue);
}
else
{
result = ConvertToResult<TResult>(key, valueOfKey);
}
return result;
}
private static TResult ConvertToResult<TResult>(string key, string valueOfKey)
{
TResult result;
try
{
result = (TResult)Convert.ChangeType(valueOfKey, typeof(TResult));
}
catch (Exception ex)
{
if (ThrowException && DefaultValue == null)
{
throw new Exception($"Failed to convert {valueOfKey} from type {valueOfKey.GetType()} to the type {typeof (TResult)}", ex);
}
result = GetDefaultValue((Func<TResult>)Convert.ChangeType(DefaultValue, typeof(Func<TResult>)));
}
return result;
}
private static TResult GetDefaultValue<TResult>(Func<TResult> defaultValue)
{
var result = default(TResult);
if (defaultValue != null)
{
try
{
result = defaultValue.Invoke();
}
catch (Exception ex)
{
if (ThrowException)
{
throw new Exception($"Failed to to invoke delegate {defaultValue} of type {defaultValue.GetType()}", ex);
}
}
}
return result;
}
}
}