parse numberstyles example convert c# generics tryparse

numberstyles - decimal.tryparse c# example



Genérico TryParse (18)

¿Qué tal algo como esto?

http://madskristensen.net/post/Universal-data-type-checker.aspx ( Archive )

/// <summary> /// Checks the specified value to see if it can be /// converted into the specified type. /// <remarks> /// The method supports all the primitive types of the CLR /// such as int, boolean, double, guid etc. as well as other /// simple types like Color and Unit and custom enum types. /// </remarks> /// </summary> /// <param name="value">The value to check.</param> /// <param name="type">The type that the value will be checked against.</param> /// <returns>True if the value can convert to the given type, otherwise false. </returns> public static bool CanConvert(string value, Type type) { if (string.IsNullOrEmpty(value) || type == null) return false; System.ComponentModel.TypeConverter conv = System.ComponentModel.TypeDescriptor.GetConverter(type); if (conv.CanConvertFrom(typeof(string))) { try { conv.ConvertFrom(value); return true; } catch { } } return false; }

Esto se puede convertir a un método genérico con bastante facilidad.

public static T Is<T>(this string input) { if (string.IsNullOrEmpty(value)) return false; var conv = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T)); if (conv.CanConvertFrom(typeof(string))) { try { conv.ConvertFrom(value); return true; } catch { } } return false; }

Intento crear una extensión genérica que use ''TryParse'' para verificar si una cadena es un tipo dado:

public static bool Is<T>(this string input) { T notUsed; return T.TryParse(input, out notUsed); }

esto no compilará ya que no puede resolver el símbolo ''TryParse''

Según entiendo, ''TryParse'' no es parte de ninguna interfaz.

¿Es esto posible de hacer?

Actualizar:

Usando las respuestas a continuación he encontrado:

public static bool Is<T>(this string input) { try { TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(input); } catch { return false; } return true; }

Funciona bastante bien, pero creo que usar excepciones de esa manera no me parece correcto.

Actualización2:

Modificado para pasar el tipo en lugar de usar genéricos:

public static bool Is(this string input, Type targetType) { try { TypeDescriptor.GetConverter(targetType).ConvertFromString(input); return true; } catch { return false; } }


Aquí hay otra opción.

Escribí una clase que hace que sea fácil registrar cualquier número de controladores TryParse . Me deja hacer esto:

var tp = new TryParser(); tp.Register<int>(int.TryParse); tp.Register<decimal>(decimal.TryParse); tp.Register<double>(double.TryParse); int x; if (tp.TryParse("42", out x)) { Console.WriteLine(x); };

Me imprimo 42 en la consola.

La clase es:

public class TryParser { public delegate bool TryParseDelegate<T>(string s, out T result); private Dictionary<Type, Delegate> _tryParsers = new Dictionary<Type, Delegate>(); public void Register<T>(TryParseDelegate<T> d) { _tryParsers[typeof(T)] = d; } public bool Deregister<T>() { return _tryParsers.Remove(typeof(T)); } public bool TryParse<T>(string s, out T result) { if (!_tryParsers.ContainsKey(typeof(T))) { throw new ArgumentException("Does not contain parser for " + typeof(T).FullName + "."); } var d = (TryParseDelegate<T>)_tryParsers[typeof(T)]; return d(s, out result); } }


Como dijiste, TryParse no es parte de una interfaz. Tampoco es miembro de ninguna clase base dada, ya que en realidad es static y las funciones static no pueden ser virtual . Entonces, el compilador no tiene forma de asegurar que T realidad tiene un miembro llamado TryParse , entonces esto no funciona.

Como dijo @Mark, puedes crear tu propia interfaz y usar tipos personalizados, pero no tienes suerte con los tipos integrados.


Cuando quería hacer casi exactamente esto, tuve que implementarlo de la manera difícil, dado el reflejo. Dado T , reflexionar sobre typeof(T) y buscar un método TryParse o Parse , invocando si lo has encontrado.


Deberías usar la clase TypeDescriptor :

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


Esta es una cuestión de ''restricciones genéricas''. Debido a que no tiene una interfaz específica, entonces está atascado a menos que siga las sugerencias de la respuesta anterior.

Para la documentación sobre esto, consulte el siguiente enlace:

http://msdn.microsoft.com/en-us/library/ms379564(VS.80).aspx

Le muestra cómo usar estas restricciones y debería darle más pistas.


Este es mi intento. Lo hice como un "ejercicio". Traté de hacerlo tan similar como " Convert.ToX () " -one existente, pero este es el método de extensión:

public static bool TryParse<T>(this String str, out T parsedValue) { try { parsedValue = (T)Convert.ChangeType(str, typeof(T)); return true; } catch { parsedValue = default(T); return false; } }


Inspirado por la solución publicada aquí por Charlie Brown, creé un TryParse genérico utilizando la reflexión que opcionalmente genera el valor analizado:

/// <summary> /// Tries to convert the specified string representation of a logical value to /// its type T equivalent. A return value indicates whether the conversion /// succeeded or failed. /// </summary> /// <typeparam name="T">The type to try and convert to.</typeparam> /// <param name="value">A string containing the value to try and convert.</param> /// <param name="result">If the conversion was successful, the converted value of type T.</param> /// <returns>If value was converted successfully, true; otherwise false.</returns> public static bool TryParse<T>(string value, out T result) where T : struct { var tryParseMethod = typeof(T).GetMethod("TryParse", BindingFlags.Static | BindingFlags.Public, null, new [] { typeof(string), typeof(T).MakeByRefType() }, null); var parameters = new object[] { value, null }; var retVal = (bool)tryParseMethod.Invoke(null, parameters); result = (T)parameters[1]; return retVal; } /// <summary> /// Tries to convert the specified string representation of a logical value to /// its type T equivalent. A return value indicates whether the conversion /// succeeded or failed. /// </summary> /// <typeparam name="T">The type to try and convert to.</typeparam> /// <param name="value">A string containing the value to try and convert.</param> /// <returns>If value was converted successfully, true; otherwise false.</returns> public static bool TryParse<T>(string value) where T : struct { T throwaway; var retVal = TryParse(value, out throwaway); return retVal; }

Se puede llamar así:

string input = "123"; decimal myDecimal; bool myIntSuccess = TryParse<int>(input); bool myDecimalSuccess = TryParse<decimal>(input, out myDecimal);

Actualizar:
También gracias a la solución de YotaXP, que me gusta mucho, creé una versión que no usa métodos de extensión pero que todavía tiene un singleton, minimizando la necesidad de hacer una reflexión:

/// <summary> /// Provides some extra parsing functionality for value types. /// </summary> /// <typeparam name="T">The value type T to operate on.</typeparam> public static class TryParseHelper<T> where T : struct { private delegate bool TryParseFunc(string str, out T result); private static TryParseFunc tryParseFuncCached; private static TryParseFunc tryParseCached { get { return tryParseFuncCached ?? (tryParseFuncCached = Delegate.CreateDelegate(typeof(TryParseFunc), typeof(T), "TryParse") as TryParseFunc); } } /// <summary> /// Tries to convert the specified string representation of a logical value to /// its type T equivalent. A return value indicates whether the conversion /// succeeded or failed. /// </summary> /// <param name="value">A string containing the value to try and convert.</param> /// <param name="result">If the conversion was successful, the converted value of type T.</param> /// <returns>If value was converted successfully, true; otherwise false.</returns> public static bool TryParse(string value, out T result) { return tryParseCached(value, out result); } /// <summary> /// Tries to convert the specified string representation of a logical value to /// its type T equivalent. A return value indicates whether the conversion /// succeeded or failed. /// </summary> /// <param name="value">A string containing the value to try and convert.</param> /// <returns>If value was converted successfully, true; otherwise false.</returns> public static bool TryParse(string value) { T throwaway; return TryParse(value, out throwaway); } }

Llámalo así:

string input = "987"; decimal myDecimal; bool myIntSuccess = TryParseHelper<int>.TryParse(input); bool myDecimalSuccess = TryParseHelper<decimal>.TryParse(input, out myDecimal);


Logré obtener algo que funciona así

var result = "44".TryParse<int>(); Console.WriteLine( "type={0}, value={1}, valid={2}", result.Value.GetType(), result.Value, result.IsValid );

Aquí está mi código

public static class TryParseGeneric { //extend int public static dynamic TryParse<T>( this string input ) { dynamic runner = new StaticMembersDynamicWrapper( typeof( T ) ); T value; bool isValid = runner.TryParse( input, out value ); return new { IsValid = isValid, Value = value }; } } public class StaticMembersDynamicWrapper : DynamicObject { private readonly Type _type; public StaticMembersDynamicWrapper( Type type ) { _type = type; } // Handle static properties public override bool TryGetMember( GetMemberBinder binder, out object result ) { PropertyInfo prop = _type.GetProperty( binder.Name, BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public ); if ( prop == null ) { result = null; return false; } result = prop.GetValue( null, null ); return true; } // Handle static methods public override bool TryInvokeMember( InvokeMemberBinder binder, object [] args, out object result ) { var methods = _type .GetMethods( BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public ).Where( methodInfo => methodInfo.Name == binder.Name ); var method = methods.FirstOrDefault(); if ( method == null ) { result = null; return false; } result = method.Invoke( null, args ); return true; } }

StaticMembersDynamicWrapper es una adaptación del http://blogs.msdn.com/b/davidebb/archive/2009/10/23/using-c-dynamic-to-call-static-members.aspx de David Ebbo (estaba lanzando AmbiguousMatchException)


No puedes hacerlo en tipos generales.

Lo que podría hacer es crear una interfaz ITryParsable y utilizarla para los tipos personalizados que implementan esta interfaz.

Aunque supongo que tienes la intención de usar esto con tipos básicos como int y DateTime . No puede cambiar estos tipos para implementar nuevas interfaces.


Si está configurado usando TryParse, puede usar reflection y hacerlo así:

public static bool Is<T>(this string input) { var type = typeof (T); var temp = default(T); var method = type.GetMethod( "TryParse", new[] { typeof (string), Type.GetType(string.Format("{0}&", type.FullName)) }); return (bool) method.Invoke(null, new object[] {input, temp}); }


También solicité un TryParse genérico recientemente. Esto es lo que se me ocurrió;

public static T? TryParse<T>(string value, TryParseHandler<T> handler) where T : struct { if (String.IsNullOrEmpty(value)) return null; T result; if (handler(value, out result)) return result; Trace.TraceWarning("Invalid value ''{0}''", value); return null; } public delegate bool TryParseHandler<T>(string value, out T result);

Entonces es simplemente una cuestión de llamar así:

var value = TryParse<int>("123", int.TryParse); var value2 = TryParse<decimal>("123.123", decimal.TryParse);


Tomado de http://blogs.msdn.com/b/davidebb/archive/2009/10/23/using-c-dynamic-to-call-static-members.aspx

al seguir esta referencia: ¿Cómo invocar el método estático en C # 4.0 con el tipo dinámico?

using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Reflection; namespace Utils { public class StaticMembersDynamicWrapper : DynamicObject { private Type _type; public StaticMembersDynamicWrapper(Type type) { _type = type; } // Handle static methods public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { var methods = _type .GetMethods(BindingFlags.FlattenHierarchy | BindingFlags.Static | BindingFlags.Public) .Where(methodInfo => methodInfo.Name == binder.Name); var method = methods.FirstOrDefault(); if (method != null) { result = method.Invoke(null, args); return true; } result = null; return false; } } public static class StaticMembersDynamicWrapperExtensions { static Dictionary<Type, DynamicObject> cache = new Dictionary<Type, DynamicObject> { {typeof(double), new StaticMembersDynamicWrapper(typeof(double))}, {typeof(float), new StaticMembersDynamicWrapper(typeof(float))}, {typeof(uint), new StaticMembersDynamicWrapper(typeof(uint))}, {typeof(int), new StaticMembersDynamicWrapper(typeof(int))}, {typeof(sbyte), new StaticMembersDynamicWrapper(typeof(sbyte))} }; /// <summary> /// Allows access to static fields, properties, and methods, resolved at run-time. /// </summary> public static dynamic StaticMembers(this Type type) { DynamicObject retVal; if (!cache.TryGetValue(type, out retVal)) return new StaticMembersDynamicWrapper(type); return retVal; } } }

Y úsalo de la siguiente manera:

public static T? ParseNumeric<T>(this string str, bool throws = true) where T : struct { var statics = typeof(T).StaticMembers(); if (throws) return statics.Parse(str); T retval; if (!statics.TryParse(str, out retval)) return null; return retval; }


Un poco tarde para la fiesta, pero esto es lo que se me ocurrió. Sin excepciones, reflejo de una sola vez (por tipo).

public static class Extensions { public static T? ParseAs<T>(this string str) where T : struct { T val; return GenericHelper<T>.TryParse(str, out val) ? val : default(T?); } public static T ParseAs<T>(this string str, T defaultVal) { T val; return GenericHelper<T>.TryParse(str, out val) ? val : defaultVal; } private static class GenericHelper<T> { public delegate bool TryParseFunc(string str, out T result); private static TryParseFunc tryParse; public static TryParseFunc TryParse { get { if (tryParse == null) tryParse = Delegate.CreateDelegate( typeof(TryParseFunc), typeof(T), "TryParse") as TryParseFunc; return tryParse; } } } }

Se requiere la clase adicional porque los métodos de extensión no están permitidos dentro de las clases genéricas. Esto permite un uso simple, como se muestra a continuación, y solo refleja la primera vez que se utiliza un tipo.

"5643".ParseAs<int>()


Una versión para obtener descendientes de XDocument.

public static T Get<T>(XDocument xml, string descendant, T @default) { try { var converter = TypeDescriptor.GetConverter(typeof (T)); if (converter != null) { return (T) converter.ConvertFromString(xml.Descendants(descendant).Single().Value); } return @default; } catch { return @default; } }


Usar try / catch para control de flujo es una política terrible. Lanzar una excepción provoca retrasos en el rendimiento mientras el tiempo de ejecución funciona alrededor de la excepción. En su lugar, valide los datos antes de convertirlos.

var attemptedValue = "asdfasdsd"; var type = typeof(int); var converter = TypeDescriptor.GetConverter(type); if (converter != null && converter.IsValid(attemptedValue)) return converter.ConvertFromString(attemptedValue); else return Activator.CreateInstance(type);


Utiliza un constructor estático para cada tipo genérico, por lo que solo debe realizar el trabajo costoso la primera vez que lo llame en un tipo determinado. Maneja todos los tipos en el espacio de nombres del sistema que tienen métodos TryParse. También funciona con versiones que aceptan nulos de cada una de esas (que son estructuras) excepto para enumeraciones.

public static bool TryParse<t>(this string Value, out t result) { return TryParser<t>.TryParse(Value.SafeTrim(), out result); } private delegate bool TryParseDelegate<t>(string value, out t result); private static class TryParser<T> { private static TryParseDelegate<T> parser; // Static constructor: static TryParser() { Type t = typeof(T); if (t.IsEnum) AssignClass<T>(GetEnumTryParse<T>()); else if (t == typeof(bool) || t == typeof(bool?)) AssignStruct<bool>(bool.TryParse); else if (t == typeof(byte) || t == typeof(byte?)) AssignStruct<byte>(byte.TryParse); else if (t == typeof(short) || t == typeof(short?)) AssignStruct<short>(short.TryParse); else if (t == typeof(char) || t == typeof(char?)) AssignStruct<char>(char.TryParse); else if (t == typeof(int) || t == typeof(int?)) AssignStruct<int>(int.TryParse); else if (t == typeof(long) || t == typeof(long?)) AssignStruct<long>(long.TryParse); else if (t == typeof(sbyte) || t == typeof(sbyte?)) AssignStruct<sbyte>(sbyte.TryParse); else if (t == typeof(ushort) || t == typeof(ushort?)) AssignStruct<ushort>(ushort.TryParse); else if (t == typeof(uint) || t == typeof(uint?)) AssignStruct<uint>(uint.TryParse); else if (t == typeof(ulong) || t == typeof(ulong?)) AssignStruct<ulong>(ulong.TryParse); else if (t == typeof(decimal) || t == typeof(decimal?)) AssignStruct<decimal>(decimal.TryParse); else if (t == typeof(float) || t == typeof(float?)) AssignStruct<float>(float.TryParse); else if (t == typeof(double) || t == typeof(double?)) AssignStruct<double>(double.TryParse); else if (t == typeof(DateTime) || t == typeof(DateTime?)) AssignStruct<DateTime>(DateTime.TryParse); else if (t == typeof(TimeSpan) || t == typeof(TimeSpan?)) AssignStruct<TimeSpan>(TimeSpan.TryParse); else if (t == typeof(Guid) || t == typeof(Guid?)) AssignStruct<Guid>(Guid.TryParse); else if (t == typeof(Version)) AssignClass<Version>(Version.TryParse); } private static void AssignStruct<t>(TryParseDelegate<t> del) where t: struct { TryParser<t>.parser = del; if (typeof(t).IsGenericType && typeof(t).GetGenericTypeDefinition() == typeof(Nullable<>)) { return; } AssignClass<t?>(TryParseNullable<t>); } private static void AssignClass<t>(TryParseDelegate<t> del) { TryParser<t>.parser = del; } public static bool TryParse(string Value, out T Result) { if (parser == null) { Result = default(T); return false; } return parser(Value, out Result); } } private static bool TryParseEnum<t>(this string Value, out t result) { try { object temp = Enum.Parse(typeof(t), Value, true); if (temp is t) { result = (t)temp; return true; } } catch { } result = default(t); return false; } private static MethodInfo EnumTryParseMethod; private static TryParseDelegate<t> GetEnumTryParse<t>() { Type type = typeof(t); if (EnumTryParseMethod == null) { var methods = typeof(Enum).GetMethods( BindingFlags.Public | BindingFlags.Static); foreach (var method in methods) if (method.Name == "TryParse" && method.IsGenericMethodDefinition && method.GetParameters().Length == 2 && method.GetParameters()[0].ParameterType == typeof(string)) { EnumTryParseMethod = method; break; } } var result = Delegate.CreateDelegate( typeof(TryParseDelegate<t>), EnumTryParseMethod.MakeGenericMethod(type), false) as TryParseDelegate<t>; if (result == null) return TryParseEnum<t>; else return result; } private static bool TryParseNullable<t>(string Value, out t? Result) where t: struct { t temp; if (TryParser<t>.TryParse(Value, out temp)) { Result = temp; return true; } else { Result = null; return false; } }


public static T Get<T>(string val) { return (T) TypeDescriptor.GetConverter(typeof (T)).ConvertFromInvariantString(val); }