Generic Tryparse

Generic TryParse

You should use the TypeDescriptor class:

public static T Convert<T>(this string input)
{
try
{
var converter = TypeDescriptor.GetConverter(typeof(T));
if(converter != null)
{
// Cast ConvertFromString(string text) : object to (T)
return (T)converter.ConvertFromString(input);
}
return default(T);
}
catch (NotSupportedException)
{
return default(T);
}
}

how to use T .TryParse in a generic Method while T is either double or Int

You could do something like this:

   public static T GetDoubleOrIntValue<T>(this string str) where T : IConvertible
{
var thisType = default(T);
var typeCode = thisType.GetTypeCode();
if (typeCode == TypeCode.Double)
{
double d;
double.TryParse(str, out d);
return (T)Convert.ChangeType(d,typeCode) ;
}
else if (typeCode == TypeCode.Int32)
{
int i;
int.TryParse(str, out i);
return (T)Convert.ChangeType(i, typeCode);
}
return thisType;
}

Then when you call it:

string d = "1.1";
string i = "3";

double doubleValue = d.GetDoubleOrIntValue<double>();
int intValue = i.GetDoubleOrIntValue<int>();

But the whole thing seems kinda silly to me.

EDIT: Saw someone else using Convert.ChangeType...which provides for a generic return type.

Generic wrapper for TryParse() in C#

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;
}
}

How to use generic Tryparse with Enum?

The TryParse method has the following signature:

TryParse<TEnum>(string value, bool ignoreCase, out TEnum result)
where TEnum : struct

It has a generic type parameter TEnum that must be a struct and that is used to determine the type of enumeration being parsed. When you don't provide it explicitly (as you did), it will take the type of whatever you provide as the result argument, which in your case is of type Enum (and not the type of the enumeration itself).

Note that Enum is a class (despite it inheriting from ValueType) and therefore it does not satisfy the requirement that TEnum is a struct.

You can solve this by removing the Type parameter and giving the method a generic type parameter with the same constraints (i.e. struct) as the generic type parameter on the TryParse function.

So try this, where I've named the generic type parameter TEnum:

private static TEnum GetEnumStringEnumType<TEnum>()
where TEnum : struct
{
string userInputString = string.Empty;
TEnum resultInputType = default(TEnum);
bool enumParseResult = false;

while (!enumParseResult)
{
userInputString = System.Console.ReadLine();
enumParseResult = Enum.TryParse(userInputString, true, out resultInputType);
}
return resultInputType;
}

To call the method, use:

GetEnumStringEnumType<MyEnum>();

Enum.TryParse not accepted in generic restricted to Enum


Seemingly System.Enum is nullable but actual enums aren't nullable.

Yes, just like System.ValueType is a reference type, but value types themselves aren't.

You just need to add a struct constraint:

private T GetEnumFilter<T>(string value) where T : struct, Enum

This compiles, for example:

private static T GetEnumFilter<T>(string value) where T : struct, Enum =>
Enum.TryParse(value, out T result) ? result : throw new Exception("Invalid value");

More generic TryParse() of line of a PLY file

Disclaimer: So this is more like a code review (you have deleted your question to early on http://codereview.stackexchange.com), but it should address your question.


Based on the nameing guidelines input parameters should be named using camelCase casing.


I don't see a reason, why you have overloaded TryParse() methods for the Face3 and Face4.

Setting the passed input parameter face (naming guidelines) = null will make it possible to return early without assigning any new object to the parameter.

In the way you had created a new Face3 the passed in IFace would have been initialized also if the TryParse() returned false.

This

public struct Face3 : IFace
{
public int V1;
public int V2;
public int V3;

public override string ToString()
{
return string.Format("3 {0} {1} {2}", V1, V2, V3);
}

internal static bool TryParse(string input, out IFace face)
{

face = null;

var args = input.Split(' ');
if (args.Length != 4)
{
return false;
}

Face3 currentFace = new Face3();
bool success = true;
success=success && int.TryParse(args[1], out currentFace.V1);
success = success && int.TryParse(args[2], out currentFace.V2);
success = success && int.TryParse(args[3], out currentFace.V3);

if (!success)
{
return false;
}
face = currentFace;
return true;
}

}

will just work, also without this

IFace face = new Face3();  // ugly: I need to instanciate the face bevore I can use "out face"  

By adding a FaceParser class which can be private and a static TryParse() method like

private class FaceParser
{
public static bool TryParse(string line, out IFace face)
{
if (Face3.TryParse(line, out face)) { return true; }
if (Face4.TryParse(line, out face)) { return true; }
return false;
}
}

which if it is private should be contained in the class where you are adding to the faces, your initial example how you parse the lines can be simplified to

foreach (string line in faceLines)
{
IFace face;
if (FaceParser.TryParse(line, out face))
{
faces.Add(face);
}
}

It seems that you use the IFace interface only as a marker interface. Adding a ToString() method to an interface is somehow superfluous, because each object already contains an overridable ToString() method. So you can simplify your interface to

public interface IFace {} 

Parse String to a Generic Type

If you want to be able to convert you could use the following method.

public T ConvertToType<T>(string input)
{
return (T)Convert.ChangeType(input, typeof(T));
}

Usage:

string input = "06/23/2016";
DateTime date = ConvertToType<DateTime>(input);

How to call TryParse dynamically?

You could call the TryParse method dynamically using Reflection. This way you won't get a time consuming Exception if the conversion fails.

This method is a slightly optimized version of this one.

    //Try Parse using Reflection
public static bool TryConvertValue<T>(string stringValue, out T convertedValue)
{
var targetType = typeof(T);
if (targetType == typeof(string))
{
convertedValue = (T)Convert.ChangeType(stringValue, typeof(T));
return true;
}
var nullableType = targetType.IsGenericType &&
targetType.GetGenericTypeDefinition() == typeof (Nullable<>);
if (nullableType)
{
if (string.IsNullOrEmpty(stringValue))
{
convertedValue = default(T);
return true;
}
targetType = new NullableConverter(targetType).UnderlyingType;
}

Type[] argTypes = { typeof(string), targetType.MakeByRefType() };
var tryParseMethodInfo = targetType.GetMethod("TryParse", argTypes);
if (tryParseMethodInfo == null)
{
convertedValue = default(T);
return false;
}

object[] args = { stringValue, null };
var successfulParse = (bool)tryParseMethodInfo.Invoke(null, args);
if (!successfulParse)
{
convertedValue = default(T);
return false;
}

convertedValue = (T)args[1];
return true;
}


Related Topics



Leave a reply



Submit