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.
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'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;
}
Is there any way to have a method return any one of a number of generic types from a method? For example, I have the following:
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
if(typeof(T) == typeof(Int32))
{
return Int32.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(Double))
{
return Double.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(String))
{
return element.Attribute(attribute).Value;
}
if(typeof(T) == typeof(ItemLookupType))
{
return Enum.Parse(typeof(T), element.Attribute(attribute).Value);
}
}
(This is only a very quick mockup, I'm aware that any production code would need to be significantly more thorough in null checks etc...)
But the compiler doesn't like it, complaining that Int32 cannot be implicitly converted to T (it doesn't work with a cast either). I can understand that. At compile time it has no way to know what T is, but I'm checking it beforehand. Is there anyway I can make this work?
I've done these types of generic methods in the past. The easiest way to get type inference is to provide a generic converter function.
public static T ParseAttributeValue<T>
(this XElement element, string attribute, Func<string, T> converter)
{
string value = element.Attribute(attribute).Value;
if (String.IsNullOrWhiteSpace(value)) {
return default(T);
}
return converter(value);
}
You can use it like the following:
int index = element.ParseAttributeValue("index", Convert.ToInt32);
double price = element.ParseAttributeValue("price", Convert.ToDouble);
You can even provide your own functions and have all the fun in the world (even return anonymous types):
ItemLookupType lookupType = element.ParseAttributeValue("lookupType",
value => Enum.Parse(typeof(ItemLookupType), value));
var item = element.ParseAttributeValue("items",
value => {
List<string> items = new List<string>();
items.AddRange(value.Split(new [] { ',' }));
return items;
});
.Net already has a bunch of great string conversion routines you can use! A TypeConverter can do most of the heavy lifting for you. Then you don't have to worry providing your own parsing implementations for built-in types.
Note that there are locale-aware versions of the APIs on TypeConverter that could be used if you need to handle parsing values expressed in different cultures.
The following code will parse values using the default culture:
using System.ComponentModel;
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
var converter = TypeDescriptor.GetConverter(typeof(T));
if (converter.CanConvertFrom(typeof(string)))
{
string value = element.Attribute(attribute).Value;
return (T)converter.ConvertFromString(value);
}
return default(T);
}
This will work for a lot of built-in types, and you can decorate custom types with a TypeConverterAttribute to allow them to participate in the type conversion game too. This means that in the future you will be able to parse new types without having to change the implementation of the ParseAttributeValue.
see: http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter.aspx
Why are you using the type parameter as the return type at all? This would work, just requires a cast after calling:
public static Object ParseAttributeValue<T>(this XElement element, string attribute)
{
if(typeof(T) == typeof(Int32))
{
return Int32.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(Double))
{
return Double.Parse(element.Attribute(attribute).Value);
}
if(typeof(T) == typeof(String))
{
return element.Attribute(attribute).Value;
}
if(typeof(T) == typeof(ItemLookupType))
{
return Enum.Parse(typeof(T), element.Attribute(attribute).Value);
}
}
Or better yet:
public static Int32 ParseAsInt32(this XElement element, string attribute)
{
return Int32.Parse(element.Attribute(attribute).Value);
}
// etc, repeat for each type
This second approach has the additional benefit of having a much higher likelihood of getting inlined, plus it will (for value types like Int32) prevent the need to box/unbox the value. Both of these will cause the method to perform somewhat faster.
Not sure if this is exactly what you want, but you can make the returns work if you cast to object first then to T
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
if (typeof(T) == typeof(Int32))
{
return (T)(object)Int32.Parse(element.Attribute(attribute).Value);
}
if (typeof(T) == typeof(Double))
{
return (T)(object)Double.Parse(element.Attribute(attribute).Value);
}
if (typeof(T) == typeof(String))
{
return (T)(object)element.Attribute(attribute).Value;
}
return default(T);
}
However you still have to provide T at compile time, calling the method like:
int value = element.ParseAttributeValue<int>("attribute");
Here's two ways of doing it...
static T ReadSetting<T>(string value)
{
object valueObj = null;
if (typeof(T) == typeof(Int32))
valueObj = Int32.Parse(value);
return (T)valueObj;
}
static dynamic ReadSetting2<T>(string value)
{
if (typeof(T) == typeof(Int32))
return Int32.Parse(value);
throw new UnsupportedException("Type is unsupported");
}
static void Main(string[] args)
{
int val1 = ReadSetting<Int32>("2");
int val2 = ReadSetting2<Int32>("3");
}
With C++ templates, this kind of thing would work, but only if each piece of code were in a different, separate specialization. The thing that makes that work is that unused function templates are not compiled (or more accurately: not fully instantiated), so the fact that a piece of code would be invalid if that copy of the template were instantiated with a different type doesn't come up.
C# is different, and AFAIK there's no specialization for generics. One way to accomplish what you are trying to do, while working within the limitations of C# would be to create one function with a more abstract return type, and use the ParseAttributeValue only to cast it to T.
So you would have:
private static Object AbstractParseValue(System.Type t, XElement element, string attribute)
and
public static T ParseAttributeValue<T>(this XElement element, string attribute)
{
return (T)AbstractParseValue(typeof(T), element, attribute);
}
I would suggest that rather than testing the type parameter every time the routine is executed, you should create a generic static class something like this:
internal static class ElementParser<T>
{
public static Func<XElement, string, T> Convert = InitConvert;
T DefaultConvert(XElement element, string attribute)
{
return Default(T); // Or maybe throw exception, or whatever
}
T InitConvert(XElement element, string attribute)
{
if (ElementParser<int>.Convert == ElementParser<int>.InitConvert)
{ // First time here for any type at all
Convert = DefaultConvert; // May overwrite this assignment below
ElementParser<int>.Convert =
(XElement element, string attribute) =>
Int32.Parse(element.Attribute(attribute).Value);
ElementParser<double>.Convert =
(XElement element, string attribute) =>
Int32.Parse(element.Attribute(attribute).Value);
// etc. for other types
}
else // We've done other types, but not this type, and we don't do anything nice for it
{
Convert = DefaultConvert;
}
return Convert(element, attribute);
}
}
public static T ParseAttributeValue(this XElement element, string attribute)
{
ElementParser<T>.Convert(element, attribute);
}
Using this approach, one will only have to do special handling the first time a particular type is used. After that, the conversion can be performed using only a single generic delegate invocation. Once could easily add any number of types, and even allow converters to be registered for any desired type at runtime.
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.