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
How to Securely Save Username/Password (Local)
Random String Generator Returning Same String
Calculating Distance Between Two Latitude and Longitude Geocoordinates
Xmlserializer Giving Filenotfoundexception at Constructor
Getting a Url with an Url-Encoded Slash
Blazor - Display Wait or Spinner on API Call
Regular Expression Groups in C#
Validate Image from File in C#
Check for Column Name in a SQLdatareader Object
Generating Permutations of a Set (Most Efficiently)
Wait Until File Is Completely Written
Serializing Private Member Data
Dynamically Add C# Properties at Runtime
Combining N Datatables into a Single Datatable
Changing the Value of an Element in a List of Structs