I just made a method that should handle GET and POST parameters (primitive types) sent by AJAX requests to the server:
protected T GetParam<T>(string key)
{
string value = HttpContext.Current.Request[key];
if (string.IsNullOrEmpty(value))
return default(T);
return (T)Convert.ChangeType(value, typeof(T));
}
Do you have any suggestions regarding improvements?
2 Answers 2
First point, small but important: give your method a proper name. GetParam
doesn't mean much and doesn't tell what it returns. Take a name like GetValueFromParameter
or GetHttpRequestValue
.
Secondly, did you test this method properly? I changed the code a bit to be able to test it, I removed the HttpContext
value and just use the parameter as value:
protected T GetHttpRequestValue<T>(string value)
{
if (string.IsNullOrEmpty(value))
return default(T);
return (T)Convert.ChangeType(value, typeof(T));
}
When I call it like this:
var longFromString = GetHttpRequestValue<long?>("0");
I get following exception:
Invalid cast from 'System.String' to 'System.Nullable`1[[System.Int64, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.
I went looking for a cause and it seems that Convert.ChangeType
has problems with nullable types. You have to use the underlying type of the nullable in order to make it work:
protected T GetHttpRequestValue<T>(string key)
{
string value = HttpContext.Current.Request[key];
if (string.IsNullOrEmpty(value))
return default(T);
var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
var convertedValue = (value == null) ? null : Convert.ChangeType(value, type);
return (T)convertedValue ;
}
Now I get following results:
GetHttpRequestValue<long?>("0"); // 0
GetHttpRequestValue<long?>(""); // null
GetHttpRequestValue<long>("1"); // 1
GetHttpRequestValue<bool>("true"); // True
GetHttpRequestValue<bool>(""); // False
GetHttpRequestValue<long?>(null); //null
GetHttpRequestValue<bool>(null); //False
You also made your method dependent of an HttpContext
, you cannot reuse it. Better would be to rename it to something like ConvertTo
and leave out the HttpContext
-line:
protected T ConvertTo<T>(string value)
{
if (string.IsNullOrEmpty(value))
return default(T);
var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
var convertedValue = (value == null) ? null : Convert.ChangeType(value, type);
return (T)convertedValue;
}
Example usage:
protected void Page_Load(object sender,EventArgs e)
{
var value = HttpContext.Current.Request["YourKey"];
var converted = ConvertTo<long?>(value);
}
Your code is still clean and the method is reusable. Notice that I use var
instead of explicitly declaring variables. This is not mandatory, I just prefer to use it. Hope this helps!
Update:
I updated the method to handle a fail on the conversion, in case you want to change qwerty
to a bool
for example. :)
protected T ConvertTo<T>(string value)
{
if (String.IsNullOrEmpty(value))
return default(T);
var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
T convertedValue = default(T);
try
{
convertedValue = (T)Convert.ChangeType(value, type);
}
catch {}
return convertedValue ;
}
This way of working swallows the exception. In case one occurs the default of T
will be returned, otherwise the converted value. Results:
ConvertTo<int>("qwerty"); //0
ConvertTo<bool>("qwerty"); //False
Update:
As stated in the comments below, you can also take the code and throw it in an extension method. Also nice for reusability and your could will also look a bit cleaner. Here goes:
public static class Extensions
{
public static T ConvertTo<T>(this string value)
{
if (String.IsNullOrEmpty(value))
return default(T);
var type = Nullable.GetUnderlyingType(typeof(T)) ?? typeof(T);
T convertedValue = default(T);
try
{
convertedValue = (T)Convert.ChangeType(value, type);
}
catch {}
return convertedValue ;
}
}
Usage:
var intFromString = "2".ConvertTo<int>();
//intFromString is an integer with value 2
-
\$\begingroup\$ Oooh, looks like I didn't test it good enough. Thanks for your input - much appreciated! I noticed that my example use was wrong. Obviously I intended to pass the request key and not the value, just as you spotted... \$\endgroup\$Johan– Johan2014年12月03日 09:03:49 +00:00Commented Dec 3, 2014 at 9:03
-
\$\begingroup\$ Another note is that
convertedValue
will never be null in theConvertTo
method \$\endgroup\$Johan– Johan2014年12月03日 09:07:28 +00:00Commented Dec 3, 2014 at 9:07 -
\$\begingroup\$ @Johan if the parameter
value
is null or empty, null will be returned. Otherwise there will be a conversion to the desired type. Note that an exception will occur when the conversion fails, for example "qwerty" as a bool. \$\endgroup\$Abbas– Abbas2014年12月03日 09:13:37 +00:00Commented Dec 3, 2014 at 9:13 -
1\$\begingroup\$ I'm smelling extension method potential here... \$\endgroup\$Jesse C. Slicer– Jesse C. Slicer2014年12月03日 16:29:53 +00:00Commented Dec 3, 2014 at 16:29
-
1\$\begingroup\$ @JesseC.Slicer loved your comment, I was thinking the same. I updated my answe. :) \$\endgroup\$Abbas– Abbas2014年12月03日 20:16:26 +00:00Commented Dec 3, 2014 at 20:16
It looks good but not perfect IMHO.
you should use braces
{}
for singleif
statements also. This is just a matter of taste, but I prefer the use of it as it makes the code less errorprone.The name of this method does not reflect what is happening. The code retrieves a value not a parameter, so a better name would be
GetValue
.