I have the following scenario where I want to pass in string and a generic type:
public class Worker {
public void DoSomeWork<T>(string value)
where T : struct, IComparable<T>, IEquatable<T> { ... }
}
At some point along the way I need to convert the string value to its T
value. But I don't want to do a straight convert as I need to perform some logic if the string cannot be converted to type T
.
I was thinking that I could try using Convert.ChangeType()
but this has the problem that if it doesn't convert it will throw an exception and I will be running the DoSomeWork()
method often enough to not have to rely on a try/catch to determine whether the convert is valid.
So this got me thinking, I know that I will be working with numeric types, hence T will be any of the following: int
, uint
, short
, ushort
, long
, ulong
, byte
, sbyte
, decimal
, float
, double
. Knowing this I thought that it might be possible to come up with a faster solution working with the fact that I know I will be using numeric types (note if T
isn't a numeric type I throw an exception)...
public class NumericWorker {
public void DoSomeWork<T>(string value)
where T : struct, IComparable<T>, IEquatable<T>
{
ParseDelegate<T> tryConverter =
SafeConvert.RetreiveNumericTryParseDelegate<T>();
...
}
}
public class SafeConvert
{
public delegate bool ParseDelegate<T>(string value, out T result);
public static ParseDelegate<T> RetreiveNumericTryParseDelegate<T>()
where T : struct, IComparable<T>, IEquatable<T>
{
ParseDelegate<T> tryParseDelegate = null;
if (typeof(T) == typeof(int))
{
tryParseDelegate = (string v, out T t) =>
{
int typedValue;
bool result = int.TryParse(v, out typedValue);
t = result ? (T)typedValue : default(T);
//(T)Convert.ChangeType(typedValue, typeof(T)) : default(T);
return result;
};
}
else if (typeof(T) == typeof(uint)) { ... }
else if (typeof(T) == typeof(short)) { ... }
else if (typeof(T) == typeof(ushort)) { ... }
else if (typeof(T) == typeof(long)) { ... }
else if (typeof(T) == typeof(ulong)) { ... }
else if (typeof(T) == typeof(byte)) { ... }
else if (typeof(T) == typeof(sbyte)) { ... }
else if (typeof(T) == typeof(decimal)) { ... }
else if (typeof(T) == typeof(float)) { ... }
else if (typeof(T) == typeof(double)) { ... }
return tryParseDelegate;
}
}
But the above has the problem that I can't write t = result ? (T)typedValue : default(T);
as the casting of typedValue
to T
causes issues and the only way I have been able to get around it thus far is by writing (T)Convert.ChangeType(typedValue, typeof(T))
. But if I do this I am just doing another convert.
Hence I was wondering if anyone knows how I could fix this problem (if you think doing the ChangeType()
is a problem) or if there is a better solution altogether that I haven't considered.