Reputation: 1435
I have the need to examine to see if an object can be converted to a specific DataType or not, and came up with this :
public static bool TryParseAll(System.Type typeToConvert, object valueToConvert)
{
bool succeed = false;
switch (typeToConvert.Name.ToUpper())
{
case "DOUBLE":
double d;
succeed = double.TryParse(valueToConvert.ToString(), out d);
break;
case "DATETIME":
DateTime dt;
succeed = DateTime.TryParse(valueToConvert.ToString(), out dt);
break;
case "INT16":
Int16 i16;
succeed = Int16.TryParse(valueToConvert.ToString(), out i16);
break;
case "INT":
Int32 i32;
succeed = Int32.TryParse(valueToConvert.ToString(), out i32);
break;
case "INT32":
Int32 i322;
succeed = Int32.TryParse(valueToConvert.ToString(), out i322);
break;
case "INT64":
Int64 i64;
succeed = Int64.TryParse(valueToConvert.ToString(), out i64);
break;
case "BOOLEAN":
bool b;
succeed = Boolean.TryParse(valueToConvert.ToString(), out b);
break;
case "BOOL":
bool b1;
succeed = bool.TryParse(valueToConvert.ToString(), out b1);
break;
}
return succeed;
}
I'm wondering is there any ways other than this? Which is more dynamic and more efficient?
Thanks!
Upvotes: 5
Views: 7522
Reputation: 17850
Here is my version of generic TryParse
method.
I believe you can use this version too:
double pi;
if(ValueTypeHelper.TryParse("3.14159", out pi)) {
// .. pi = 3.14159
}
...
string eStr = "2.71828";
float e;
if(eStr.TryParse(out e)) {
// .. e = 2.71828f
}
...
static class ValueTypeHelper {
static IDictionary<Type, Delegate> cache = new Dictionary<Type, Delegate>();
public static bool TryParse<T>(this string valueStr, out T result) {
Delegate d = null;
if(!cache.TryGetValue(typeof(T), out d)) {
var mInfos = typeof(T).GetMember("TryParse", MemberTypes.Method, BindingFlags.Static | BindingFlags.Public);
if(mInfos.Length > 0) {
var s = Expression.Parameter(typeof(string));
var r = Expression.Parameter(typeof(T).MakeByRefType());
d = Expression.Lambda<TryParseDelegate<T>>(
Expression.Call(mInfos[0] as MethodInfo, s, r), s, r).Compile();
}
cache.Add(typeof(T), d);
}
result = default(T);
TryParseDelegate<T> tryParse = d as TryParseDelegate<T>;
return (tryParse != null) && tryParse(valueStr, out result);
}
delegate bool TryParseDelegate<T>(string valueStr, out T result);
}
Update: Here is a bit more "modern" and thread-safe version
static class ValueTypeHelper {
static ConcurrentDictionary<Type, Delegate> cache = new ConcurrentDictionary<Type, Delegate>();
public static bool TryParse<T>(this string valueStr, out T result) {
var tryParse = cache.GetOrAdd(typeof(T), t => {
// find method with static bool TryParse(string s, out T result) signature
var parameterTypes = new Type[] { typeof(string), typeof(T).MakeByRefType() };
var mInfo_TryParse = t.GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, parameterTypes, null);
if(mInfo_TryParse != null) {
// Build method dynamically
var s = Expression.Parameter(parameterTypes[0]);
var result = Expression.Parameter(parameterTypes[1]);
return Expression.Lambda<TryParseDelegate<T>>(
Expression.Call(mInfo_TryParse, s, result), s, result).Compile();
}
return null;
}) as TryParseDelegate<T>;
if(tryParse == null) {
result = default(T);
return false;
}
return tryParse(valueStr, out result);
}
delegate bool TryParseDelegate<T>(string valueStr, out T result);
}
Upvotes: 3
Reputation: 587
I have combined both DmitryG's and RezaRahmati's suggested solutions:
static class GenericValueConverter
{
public static bool TryParse<T>(this string input, out T result)
{
bool isConversionSuccessful = false;
result = default(T);
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
{
try
{
result = (T)converter.ConvertFromString(input);
isConversionSuccessful = true;
}
catch { }
}
return isConversionSuccessful;
}
}
void Main()
{
double pi;
if (GenericValueConverter.TryParse("3,14159", out pi)) //Use right decimal point seperator for local culture
{
pi.Dump(); //ConsoleWriteline for LinqPad
//pi=3,14159
}
string dtStr = "2016-12-21T16:34:22";
DateTime dt;
if (dtStr.TryParse(out dt))
{
dt.Dump(); //ConsoleWriteline for LinqPad
//dt=21.12.2016 16:34:22
}
string guidStr = "D430831B-03B0-44D5-A971-4E73AF96B5DF";
Guid guid;
if (guidStr.TryParse(out guid))
{
guid.Dump(); //ConsoleWriteline for LinqPad
//guid=d430831b-03b0-44d5-a971-4e73af96b5df
}
}
Upvotes: 0
Reputation: 19843
You should use the TypeDescriptor class:
public static T Convert<T>(this string input)
{
var converter = TypeDescriptor.GetConverter(typeof(T));
if(converter != null)
{
//Cast ConvertFromString(string text) : object to (T)
return (T)converter.ConvertFromString(input);
}
return default(T);
}
of course this will throw an exception if the conversion fails so you will want to try/catch it.
Upvotes: 4