I'm using the following methods to provide quick, inline access to the TryParse() method of various Type classes. Basically I want to be able to parse a string coming from a web service if possible or return a default value if not.
private Int64 Int64Parse(string value) {
Int64 result;
if (!Int64.TryParse(value, out result)) { return default(Int64); }
return result;
}
private DateTime DateTimeParse(string value) {
DateTime result;
if (!DateTime.TryParse(value, out result)) { return default(DateTime); }
return result;
}
private Decimal DecimalParse(string value) {
Decimal result;
if (!Decimal.TryParse(value, out result)) { return default(Decimal); }
return result;
}
These are extremely repetitive, suggesting, to me, that there may be a way to wrap them into a single generic method.
I'm stuck at the following but not sure how to proceed or how to search for how to proceed.
private T ParseString<T>(string value) {
T result;
if (!T.TryParse(value, out result)) { return default(T); }
return result;
}
Any help would be appreciated.
Thanks.
==Edit==
To add some context. This is for a listener receiving postbacks from a specific credit card billing company. I'm not doing validation at this step because that's being done in the business rules steps later. For example, I don't care if bank_batch_number comes in as an int, string or freeze-dried rodent; I'm not going to halt with an exception if I can't cleanly log a field I don't use. I do care that ext_product_id exists in our DB and has a price matching currency_amount_settled in the message; if that test fails then the transaction is put on hold, a warning is logged, and our CS staff and myself will be alerted.
The culture thing mentioned below is sage advice though.
No, the methods are basically entirely separate - the compiler doesn't know that DateTime.TryParse is similar in any way to Int64.TryParse etc.
You could create a Dictionary<Type, Delegate> to map from the target type to the method, and then write something like:
private delegate bool Parser<T>(string value, out T result);
private T Parse<T>(string value) where T : struct
{
// TODO: Validate that typeof(T) is in the dictionary
Parser<T> parser = (Parser<T>) parsers[typeof(T)];
T result;
parser(value, out result);
return result;
}
You can populate the dictionary like this:
static readonly Dictionary<Type, Delegate> Parsers = CreateParsers();
static Dictionary<Type, Delegate> CreateParsers()
{
var parsers = new Dictionary<Type, Delegate>();
AddParser<DateTime>(parsers, DateTime.TryParse);
AddParser<Int64>(parsers, Int64.TryParse);
return parsers;
}
static void AddParser<T>(Dictionary<Type, Delegate> parsers, Parser<T> parser)
{
parsers[typeof(T)] = parser;
}
Note that the TryParse pattern states that the value of the out parameter will be the default value for that type anyway, so you don't need your conditional logic. That means even your repetitive methods can become simpler:
private static Decimal DecimalParse(string value) {
Decimal result;
Decimal.TryParse(value, out result);
return result;
}
As an aside, note that by default the TryParse pattern will use the thread's current culture. If this is being used to parse incoming data from a web service, I'd strongly recommend that you use the invariant culture instead. (Personally I wouldn't silently ignore bad data either, but I assume that's deliberate.)
Why not just use a simple extension method?
Jon Skeet's answer about just using the default result from the various TryParse methods is good. There is still a nice aspect of the extension methods, though. If you are doing this a lot, you can accomplish the same thing in the calling code (plus optionally specifying an explicit default) in one line of code rather than three.
-- EDIT -- I do realize that in my original answer I basically just provided a slightly different way of doing the same thing the author was already doing. I caught this earlier today when I was real busy, thought the delegate and custom parser stuff looked like it might be a bit much, then cranked out an answer without really taking the time to completely understand what the question was. Sorry.
How about the following, which uses an (overloaded) extension method and reflection? Refer to https://stackoverflow.com/a/4740544/618649
Caveat Emptor: my example does not account for you trying to convert types that do not have a TryParse method. There should be some exception handling around the GetMethod call, and so on.
/* The examples generates this output when run:
0
432123
-1
1/1/0001 12:00:00 AM
1/1/1970 12:00:00 AM
1/30/2013 12:00:00 PM
-1
12342.3233443
*/
class Program
{
static void Main ( string[] args )
{
Debug.WriteLine( "blah".Parse<Int64>() );
Debug.WriteLine( "432123".Parse<long>() );
Debug.WriteLine( "123904810293841209384".Parse<long>( -1 ) );
Debug.WriteLine( "this is not a DateTime value".Parse<DateTime>() );
Debug.WriteLine( "this is not a DateTime value".Parse<DateTime>( "jan 1, 1970 0:00:00".Convert<DateTime>() ) );
Debug.WriteLine( "2013/01/30 12:00:00".Parse<DateTime>() );
Debug.WriteLine( "this is not a decimal value".Parse<decimal>( -1 ) );
Debug.WriteLine( "12342.3233443".Parse<decimal>() );
}
}
static public class Extensions
{
static private Dictionary<Type,MethodInfo> s_methods = new Dictionary<Type, MethodInfo>();
static public T Parse<T> ( this string value ) where T : struct
{
return value.Parse<T>( default( T ) );
}
static public T Parse<T> ( this string value, T defaultValue ) where T : struct
{
// *EDITED* to cache the Reflection lookup--NOT thread safe
MethodInfo m = null;
if ( s_methods.ContainsKey( typeof( T ) ) )
{
m = s_methods[ typeof( T ) ];
}
else
{
m = typeof( T ).GetMethod(
"TryParse"
, BindingFlags.Public | BindingFlags.Static
, Type.DefaultBinder
, new[] { typeof( string ), typeof( T ).MakeByRefType() }
, null
);
s_methods.Add( typeof( T ), m );
}
var args = new object[] { value, null };
if( (bool)m.Invoke( null, args ))
{
return (T) args[ 1 ];
}
return defaultValue;
}
}
public delegate bool TryParseDelegate<T>(string str, out T value);
public static T ParseOrDefault<T>(string str, TryParseDelegate<T> parse)
{
T value;
return parse(str, out value) ? value : default(T);
}
You can call it like:
long l = ParseOrDefault<long>("12345", long.TryParse);
This is a method I sometimes use. If performance is a major concern then this is not the way to go, as the try-catch block and the call to ChangeType are going to slow you down a good bit more than a type-specific TryParse.
public static bool TryFromString<T>(string value, out T convertedValue)
{
Type t = typeof(T);
convertedValue = default(T);
if (t.Name == "Nullable`1")
t = System.Nullable.GetUnderlyingType(t);
if (value != null)
{
try
{
convertedValue = (T)System.Convert.ChangeType(value, t, CultureInfo.CurrentCulture);
return true;
}
catch
{
}
}
return false;
}
Related
I've looked through many questions that are similar to this, but none of them really touched on what I precisely want to do. What I am trying to do is read from an external source a list of variables that also include their data type into a string array:
Example:
ID/Key Type Value/Data;
varName1 bool true;
varName2 string str;
varName3 int 5;
I then store these are objects into a dictionary as objects containing several strings, with the ID also serving as the key.
What I want to do is now create a method that uses a switch statement that casts the string into the correct datatype, and returns it without having to specify anything in the method call. The function should look something like this:
public ??? Method(string key)
{
if(dictionary.ContainsKey(ID))
{
Var temp = dictionary[ID];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
The method call should look something like this:
int x = Method(string key);
string word = Method(string key);
bool isTrue = Method(string key);
Maybe I've missed something, but I have yet to find something that really does something quite like this. Any and all thoughts about this are welcome as well.
In C# 7 you have the option to return multiple values from a method like this:
public (string SomeString, int SomeInt) DoSomething() { ... }
You can get the values like this:
var result = DoSomething();
Console.WriteLine(result.SomeString);
Console.WriteLine(result.SomeInt.ToString());
Or
(var someString, var someInt) = DoSomething();
Console.WriteLine(someString);
Console.WriteLine(someInt.ToString());
This works below the surface with a Tuple and you are not restricted to only 2 values. I don't know how many you can return but I suggest when you need to return that many values, create a class.
More info: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/
Update
I believe a lot of people are arriving at this question because they're looking for ways to return multiple values generally, not necessarily for the purposes given in the original question. If this is what you want, there are a few options to choose from.
If the combination of your returned types represents a concept that may be useful outside of your method call, consider creating a type to represent that concept. C#'s records provide a nice, concise way to do that:
public record ExtractedValue(bool? BooleanValue, string? StringValue, int? IntValue);
public ExtractedValue Method(string key)
{
...
}
If this is the only place these values will appear together, and it's not really worth coming up with a named type to represent the values, you can also use a Value Tuple. Just be aware that there are some behavioral implications that might bite you if you plan to use the type for things like serialization.
public (bool? BooleanValue, string? StringValue, int? IntValue) Method(string key)
{
...
}
Original Answer
The compiler has no way to distinguish between the three method calls you've provided, because they all look like Method(key);
One option is to return an object and then expect the consuming code to cast it to what they want:
public object Method(string key)
{
if(dictionary.ContainsKey(key))
{
var temp = dictionary[key];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
...
int x = (int) Method(key);
string word = (string) Method(key);
bool isTrue = (bool) Method(key);
You could also use the dynamic keyword to make the cast implicit:
public dynamic Method(string key)
{
if(dictionary.ContainsKey(key))
{
var temp = dictionary[key];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
...
int x = Method(key);
string word = Method(key);
bool isTrue = Method(key);
However, dynamic is a very powerful concept, and it's easy for it to get out of hand, so you have to be really careful with that.
It seems to me that you're expecting your calling code to know which type of object it's expecting to get for each key. It seems like maybe the best approach is to just let the user supply that information:
public T Method<T>(string key)
{
if(dictionary.ContainsKey(key))
return (T) Convert.ChangeType(dictionary[key].Value, typeof(T));
return default(T);
}
...
int x = Method<int>(key);
string word = Method<string>(key);
bool isTrue = Method<bool>(key);
That way, there's no need to track the Type value in your dictionary objects in the first place.
The return type of a function must be typed. As with any other variable or operation, any type that inherits from the specified type is a valid return value (which is why object allows anything as a value).
Personally i dont think it is useful to make one method with multiple return types but if you really want to have one method with multiple return types, you could use the dynamic type in .NET 4.0:
private static void Main(string[] args)
{
int x = Method("varName3");
string word = Method("varName2");
bool isTrue = Method("varName1");
}
private static dynamic Method(string key)
{
var dictionary = new Dictionary<string, KeyValuePair<Type, object>>()
{
{ "varName1", new KeyValuePair<Type, object>(typeof(bool), false) },
{ "varName2", new KeyValuePair<Type, object>(typeof(string), "str") },
{ "varName3", new KeyValuePair<Type, object>(typeof(int), 5) },
};
if (dictionary.ContainsKey(key))
{
return dictionary[key].Value;
}
return null;
}
Hope it helps
I have been playing around with converting a string to a value type in .NET, where the resulting value type is unknown. The problem I have encountered in my code is that I need a method which accepts a string, and uses a "best fit" approach to populate the resulting value type. Should the mechanism not find a suitable match, the string is returned.
This is what I have come up with:
public static dynamic ConvertToType(string value)
{
Type[] types = new Type[]
{
typeof(System.SByte),
typeof(System.Byte),
typeof(System.Int16),
typeof(System.UInt16),
typeof(System.Int32),
typeof(System.UInt32),
typeof(System.Int64),
typeof(System.UInt64),
typeof(System.Single),
typeof(System.Double),
typeof(System.Decimal),
typeof(System.DateTime),
typeof(System.Guid)
};
foreach (Type type in types)
{
try
{
return Convert.ChangeType(value, type);
}
catch (Exception)
{
continue;
}
}
return value;
}
I feel that this approach is probably not best practice because it can only match against the predefined types.
Usually I have found that .NET accommodates this functionality in a better way than my implementation, so my question is: are there any better approaches to this problem and/or is this functionality implemented better in .NET?
EDIT: Note that the ordering of types in the array is so that the "best fit" occurs as accurately as possible for the given types.
EDIT: as per miniBill's request, this I how the method might be used (simple example!):
JsonDictionary["myKey"] = ConvertToType("255"); // 255 is a stringified json value, which should be assigned to myKey as a byte.
Your method isn't ideal as its going to cause a series of exceptions if value is not a SByte.
Seeing as all of these types share a common method .TryParse(string, out T) we can use reflection extract the method and call it for each type. I made the method an extension method on string and also factored out the Type[] array into its own lazy loaded property for faster use.
public static class StringExtensions
{
public static dynamic ConvertToType(this string value)
{
foreach (Type type in ConvertibleTypes)
{
var obj = Activator.CreateInstance(type);
var methodParameterTypes = new Type[] { typeof(string), type.MakeByRefType() };
var method = type.GetMethod("TryParse", methodParameterTypes);
var methodParameters = new object[] { value, obj };
bool success = (bool)method.Invoke(null, methodParameters);
if (success)
{
return methodParameters[1];
}
}
return value;
}
private static Type[] _convertibleTypes = null;
private static Type[] ConvertibleTypes
{
get
{
if (_convertibleTypes == null)
{
_convertibleTypes = new Type[]
{
typeof(System.SByte),
typeof(System.Byte),
typeof(System.Int16),
typeof(System.UInt16),
typeof(System.Int32),
typeof(System.UInt32),
typeof(System.Int64),
typeof(System.UInt64),
typeof(System.Single),
typeof(System.Double),
typeof(System.Decimal),
typeof(System.DateTime),
typeof(System.Guid)
};
}
return _convertibleTypes;
}
}
}
Usage:
string value = "2391203921";
dynamic converted = value.ConvertToType();
Your approach would work but, as you say, it's not that elegant.
I think you have a couple of ways to improve this code:
Move the array out of the function, as psubsee2003 said
Use the TryParse methods for cheaper testing (no catching involved) (e.g.: Int32.TryParse)
Actually write a parser that, after trimming,
Checks if the number is a GUID
Does it have '-' in it at a position > 0?
if(Guid.TryParse)
return result
return string (it can't be a number!)
Checks if the number is fractional (does it have a dot in it?)
Tries to convert to single, double, decimal using the various TryParse
If it fails return string
Does it start with a minus?
Try and parse as Int64, then check size and see where if fits (<256 -> ubyte, < 65536 ushort...)
If it fails return string
Try and parse as Int64
If it works check minimum size it fits into
If it fails it could be an integer, but too big, try parsing as double, if it fails return string
This is something I wrote previously that might be a help:
public static Boolean CanCovertTo(this String value, Type type)
{
var targetType = type.IsNullableType() ? Nullable.GetUnderlyingType(type) : type;
TypeConverter converter = TypeDescriptor.GetConverter(targetType);
return converter.IsValid(value);
}
The basic idea is if you pass the string and a Type that you want to test, you can check if a conversion will be valid before attempting to covert.
The problem with this design is that TypeConverter.IsValid() is just a wrapper (with some exception handling) for TypeConverter.CanConvertFrom() so you really aren't eliminating the exception handling, but since it is part of the BCL, I tend to think that is going to be a better implementation.
So you can implement this like so:
private static Type[] defaultTypes = new Type[]
{
typeof(System.SByte),
typeof(System.Byte),
typeof(System.Int16),
typeof(System.UInt16),
typeof(System.Int32),
typeof(System.UInt32),
typeof(System.Int64),
typeof(System.UInt64),
typeof(System.Single),
typeof(System.Double),
typeof(System.Decimal),
typeof(System.DateTime),
typeof(System.Guid)
};
public static dynamic ConvertToType(string value)
{
return ConvertToType(value, defaultTypes);
}
public static dynamic ConvertToType(string value, Type[] types)
{
foreach (Type type in types)
{
if (!value.CanConvertTo(type))
continue;
return Convert.ChangeType(value, type);
}
return value;
}
There is not really a great way to do this without the exception handling (even the exception handling in the TypeConverter.IsValid method), so you have to live with it if you really need such a method. But you can limit the need for the exception handling if you implement some of the suggestions in miniBill's answer in addition to some improvements in the design.
You could use Reflection to handle all the Parse types by calling the TryParse method, this will be a bit faster than handling multiple exceptions using ChangeType
public Type[] PredefinedTypes = new Type[]
{
typeof(System.SByte),
typeof(System.Byte),
typeof(System.Int16),
typeof(System.UInt16),
typeof(System.Int32),
typeof(System.UInt32),
typeof(System.Int64),
typeof(System.UInt64),
typeof(System.Single),
typeof(System.Double),
typeof(System.Decimal),
typeof(System.DateTime),
typeof(System.Guid)
};
public dynamic ConvertToType(string value)
{
foreach (var predefinedType in PredefinedTypes.Where(t => t.GetMethods().Any(m => m.Name.Equals("TryParse"))))
{
var typeInstance = Activator.CreateInstance(predefinedType);
var methodParamTypes = new Type[] { typeof(string), predefinedType.MakeByRefType() };
var methodArgs = new object[] { value, typeInstance };
if ((bool)predefinedType.GetMethod("TryParse", methodParamTypes).Invoke(predefinedType, methodArgs))
{
return methodArgs[1];
}
}
return value
}
I have an application containing a certain number of custom TypeConverter. They work well when used in the context of XML parsing.
On another side I am invoking class constructors (based on some previously defined XML tag) using the following (that works so far):
Type MyClass = TypeDelegator.GetType( FullClassName ); // Get the class type
if( MyClass != null ) { // If we find a matching type
ConstructorInfo[] CtorInfos = MyClass.GetConstructors(); // Get constructor infos
if( CtorInfos != null ) { // If we could find a ctor
if( CtorInfos.Length == 1 ) { // We expect 1 Ctor with args
CtorInfos[0].Invoke( new object[] { CtorArg1, CtorArg2 } );
}
}
}
Now I am trying to reuse the TypeConverter from within the invoked constructor. But it does not seems to work. I have been using the regular GetConverter method:
MyType myVar = (MyType)TypeDescriptor.GetConverter( typeof( MyType ) ).ConvertFrom( "1;2;3;4" );
The type class is similar to the following:
public class MyType {
private int PrivateField;
public MyType() { }
public MyType( String Arg1, Char Arg2 ) { }
public int Prop1 { get { return ( 4 ); } }
public int Prop2 {
get { return ( PrivateField ); }
set { PrivateField = value; }
}
}
Digging into the problem it seems that TypeDescriptor.GetConverter does not find the custom type converter (that are part of the same assembly).
var debugVar = TypeDescriptor.GetConverter( typeof( MyType ) );
always return a TypeConverter as opposed to an expected "TypeConverterMyType". That make me think "TypeConverterMyType" is not accessible probably because of the invoke.
[Update]
It seems that the TypeDescriptor.GetConverter works for enum types but not for class based type. I think I am passing next to an important part of the puzzle... :?
So the question :
1- Is it actually possible to access a custom type converter from an invoked method?
2- Is there a better/smarter way to handle this?
3- I am using .Net 3.5, should I expect the same behaviour if I upgrade to 4.0 or 4.5?
Code taken from here
I would like to hear some expert opinions on this extension method. I do plan to use it, but would like to hear about any known problems i may face.
Am i better of using on primative types TryParse methods?
public static T? TryParse<T>(this object obj) where T : struct
{
if (obj == null) return null;
T? result = null;
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
{
try
{
string str = obj.ToString();
result = (T)converter.ConvertFromString(str);
}
catch (Exception ex)
{
throw ex;
}
}
return result;
}
The TryParse pattern is best following the standard pattern, which allows use with non-structs, too:
public static bool TryParse<T>(string s, out T value) {
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
try {
value = (T) converter.ConvertFromString(s);
return true;
} catch {
value = default(T);
return false;
}
}
Note I've accepted a string here, because that is what me most commonly mean by TryParse; otherwise, Convert.ChangeType might be more appropriate.
I see no reason for this to be an extension method (as per this in the question's example), and certainly it is inadvisable to pollute object with too many extension methods.
The extensions below might be useful to you. They work on any type that has a Parse or TryParse method...
They come from my Extensions library here:
http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx
Although that project is probably a bit out-of-date...I'll have to update it as some point :-D
Hope this helps!
public static class StringExtensions
{
public static TOut ParseOrDefault<TOut>(this string input)
{
return input.ParseOrDefault(default(TOut));
}
public static TOut ParseOrDefault<TOut>(this string input, TOut defaultValue)
{
Type type = typeof(TOut);
MethodInfo parseMethod = type.GetMethod("Parse", new Type[] { typeof(string) });
if (parseMethod != null)
{
var value = parseMethod.Invoke(null, new string[] { input });
return (value is TOut ? (TOut)value : defaultValue);
}
else { return defaultValue; }
}
public static bool TryParseOrDefault<TOut>(this string input, out TOut output)
{
return input.TryParseOrDefault(out output, default(TOut));
}
public static bool TryParseOrDefault<TOut>(this string input, out TOut output, TOut defaultValue)
{
output = defaultValue;
Type type = typeof(TOut);
MethodInfo parseMethod = type.GetMethod(
"TryParse",
new Type[] { typeof(string), typeof(TOut).MakeByRefType() });
if (parseMethod != null)
{
object[] parameters = new object[] { input, output };
var value = parseMethod.Invoke(null, parameters);
if (value is bool)
{
bool successful = (bool)value;
if (successful)
{
output = (TOut)parameters[1];
return true;
}
}
}
return false;
}
}
Generics are most useful when you want to vary the public contract of a method or class, and the internals of the method or class don't really care (or care much) about the type that varies.
Some examples:
List<T> is a collection you can put things in, and internally the class doesn't care (much) about what that type is.
T System.Linq.Enumerable.First<T>(IEnumerable<T> source) returns the first element out of a bunch of elements. This method doesn't need to know internally what type that is in order to get the job done.
By contrast, a parsing method must change its behavior based on the type of the result. In the supplied method, there is Strategy which pushes the behaviors out to other methods, but there is a runtime cost for that choice.
The alternative is to let the caller (who must know the Type or they couldn't call the generic method with it), pick the converter. This choice is able to be made at design time or compile time and so incurs 0 runtime cost.
Side Note: Please don't use the re-throw everything idiom. All it does is reset the call stack and you don't ever want to do that.
catch (Exception ex)
{
throw ex;
}
For simpler code, you can do this:
T value = (T)Convert.ChangeType(value, typeof(T));
Credit to Thomas Levesque at https://stackoverflow.com/a/1465930/24315.
It uses reflection and thus may be slow, if performance is an issue.
I am trying to write a generic Parse method that converts and returns a strongly typed value from a NamedValueCollection. I tried two methods but both of these methods are going through boxing and unboxing to get the value. Does anyone know a way to avoid the boxing? If you saw this in production would you not like it, how bad is it for performance?
Usuage:
var id = Request.QueryString.Parse<int>("id");
Attempt #1:
public static T Parse<T>(this NameValueCollection col, string key)
{
string value = col[key];
if (string.IsNullOrEmpty(value))
return default(T);
if (typeof(T) == typeof(int))
{
//return int.Parse(value); // cannot convert int to T
//return (T)int.Parse(value); // cannot convert int to T
return (T)(object)int.Parse(value); // works but boxes
}
if (typeof(T) == typeof(long))
{
return (T)(object)long.Parse(value); // works but boxes
}
...
return default(T);
}
Attempt #2 (using reflection):
public static T Parse<T>(this NameValueCollection col, string key)
{
string value = col[key];
if (string.IsNullOrEmpty(value))
return default(T);
try
{
var parseMethod = typeof(T).GetMethod("Parse", new Type[] { typeof(string) });
if (parseMethod == null)
return default(T);
// still boxing because invoke returns an object
var parsedVal = parseMethod.Invoke(null, new object[] { value });
return (T)parsedVal;
}
// No Proper Parse Method found
catch(AmbiguousMatchException)
{
}
return default(T);
}
public static T Parse<T>(this NameValueCollection col, string key)
{
return (T)Convert.ChangeType(col[key], typeof(T));
}
I'm not entirely sure of ChangeType boxes or not (I guess reading the docs would tell me, but I'm pressed for time right now), but at least it gets rid of all that type-checking. The boxing overhead is not very high, though, so I wouldn't worry too much about it. If you're worried about run-time type consistency, I'd write the function as:
public static T Parse<T>(this NameValueCollection col, string key)
{
T value;
try
{
value = (T)Convert.ChangeType(col[key], typeof(T));
}
catch
{
value = default(T);
}
return value;
}
This way the function won't bomb if the value cannot be converted for whatever reason. That means, of course, that you'll have to check the returned value (which you'd have to do anyway since the user can edit the querystring).
I think you are over estimating the impact of the boxing/unboxing. The parse method will have a much bigger overhead (string parsing), dwarfing the boxing overhead. Also all the if statements will have a bigger impact. Reflection has the biggest impact of all.
I'd would not like to see this kind of code in production, as there is a cleaner way of doing it. The major problem I have with it is the large number of if statements you will need to cover all cases and the fact that someone could pass any old type to it.
What I would do is write a parse function for each type I want to parse (ie ParseInt()). It's clearer and it is well defined what the function will try to do. Also with short static methods, the compiler is more likely to inline them, saving a function call.
I think this is a bad application of generics, any particular reason for doing it this way?
I'll add a little undocumented way:
public static T Convert<T>()
{
if (typeof(T) == typeof(int))
{
int a = 5;
T value = __refvalue(__makeref(a), T);
return value;
}
else if (typeof(T) == typeof(long))
{
long a = 6;
T value = __refvalue(__makeref(a), T);
return value;
}
throw new NotImplementedException();
}
There is little documentation about them, but they work as of C# 4.0. Read for example here Hidden Features of C#? Remember that undocumented means unsupported, blah blah blah could not work in the future blah blah blah if you use them the devil will come for you blah blah blah :-)
For better readability, you could use a generic dictionary with an anonymous function as follows:
var parserFuncs = new Dictionary<Type, Func<string, object>>() {
{ typeof(int), p => (int) int.Parse(p) },
{ typeof(bool), p => (bool) bool.Parse(p) },
{ typeof(long), p => (long) long.Parse(p) },
{ typeof(short), p => (short) short.Parse(p) },
{ typeof(DateTime), p => (DateTime) DateTime.Parse(p) }
/* ...same for all the other primitive types */
};
return (T) parserFuncs[typeof(T)](value);
Another suggestion for implementation, using a TryParse or Parse method with a generic approach. I wrote this originally to convert strings parsed from a csv file into different types, int, decimal, list, etc.
public static bool TryParse<T>(this string value, out T newValue, T defaultValue = default(T))
where T : struct, IConvertible
{
newValue = defaultValue;
try
{
newValue = (T)Convert.ChangeType(value, typeof(T));
}
catch
{
return false;
}
return true;
}
public static T Parse<T>(this string value)
where T : struct, IConvertible
{
return (T) Convert.ChangeType(value, typeof (T));
}
Here, the try parse method first sets the newValue to the default value, then tries to convert value to type T and return the newValue as type T. If the conversion fails, it returns the default value of T.
The Parse method, simply tries to do the conversion, however if its not fail safe and will throw an exception if the conversion fails.
Am I too late?
static Dictionary<Type, Delegate> table =
new Dictionary<Type, Delegate>{
{ typeof(int), (Func<string,int>)Int32.Parse },
{ typeof(double), (Func<string,double>)Double.Parse },
// ... as many as you want
};
static T Parse<T>(string str)
{
if (!table.TryGet(typeof(T), out Delegate func))
throw new ArgumentException();
var typedFunc = (Func<string, T>)func;
return typedFunc(str);
}
When in trouble with types, try delegates and dicts!
int value = int.Parse(Request.QueryString["RecordID"]);
Here's a suggestion for implementation, following Robert Wagner's logic, but using a generic approach to reduce duplication:
public static int ParseInt32(this NameValueCollection col, string key)
{
return Parse(col, key, int.Parse);
}
public static double ParseDouble(this NameValueCollection col, string key)
{
return Parse(col, key, double.Parse);
}
private static T Parse<T>(NameValueCollection col, string key, Func<string, T> parse)
{
string value = col[key];
if (string.IsNullOrEmpty(value))
return default(T);
return parse(value);
}
Truth be told, returning zero for a null or empty string scares me; this could cause problems if some values are legitimately zero. Instead, I would have the methods return nullables (int?, double?, etc.), which is a slightly more compact approach than the out-parameter pattern used for the framework TryParse methods. You could do this:
public static int? ParseInt32(this NameValueCollection col, string key)
{
return Parse(col, key, int.Parse);
}
public static double? ParseDouble(this NameValueCollection col, string key)
{
return Parse(col, key, double.Parse);
}
private static T? Parse<T>(NameValueCollection col, string key, Func<string, T> parse)
where T : struct
{
string value = col[key];
if (string.IsNullOrEmpty(value))
return default(T?);
return parse(value);
}
But that would still throw an exception for non-null-or-empty strings that aren't numeric. It's better to use TryParse. The built-in Func delegates don't support ref or out parameters, so you'd have to declare your own delegate type, but that is fairly trivial.