2012-07-14 17 views
8

¿Hay alguna manera de llamar al TryParse de forma dinámica? Algún tipo de:¿Cómo llamar a TryParse de forma dinámica?

public static bool TryParse<T>(string toConvert, out T result) 

Por supuesto uno puede usar Typeonverters para esto. Sin embargo, una conversión inválida dará como resultado una excepción y quiero deshacerme de esto.

+0

Tal vez podría utilizar algo de System.Reflection. No he tratado los genéricos con Reflection, pero podría ir como get type info, ver si 'TryParse()' existe, si es así, 'Invoke()', de lo contrario devolvería false. – cyanic

+0

Relacionados: http://stackoverflow.com/a/6160588/445517 – CodesInChaos

+0

En particular, consulte http://stackoverflow.com/a/2961921/103167 Solo agregue copiando el resultado nuevamente. –

Respuesta

9

Puede llamar al método TryParse dinámicamente con Reflection. De esta forma, no obtendrá una Excepción lenta si la conversión falla.

Este método es una versión ligeramente optimizada de este 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; 
} 
+0

Bueno. Una sugerencia: en el bloque 'if (nullableType)', cuando compruebe 'stringValue' para' null', tal vez debería decir 'string.IsNullOrEmpty (stringValue)' en su lugar. La razón por la que creo que sí es que 'Nullable <>. ToString()' devuelve '" "' cuando 'HasValue' es falso. Por lo tanto, la cadena vacía se puede considerar una representación de cadena válida para, p. '(int?) null'. –

+1

Gracias por la entrada. Sin embargo, si llama a este método con "" para convertir un Nullable , el valor de salida será nulo y el valor de retorno será falso. Esto es correcto ya que "" no debería ser un valor válido para analizar int. Si utilizara string.IsNullOrEmpty, el valor de retorno sería verdadero, lo cual no sería correcto. –

+1

Eso está completamente bien. Pero significa que un 'Nullable ' no hará "ida y vuelta". Supongamos que tiene: 'int? i = nulo; cadena s = i.ToString(); ¿En t? tmp; bool canParse = TryConvertValue (s, out tmp); '. Entonces 'canParse' será falso incluso si la cadena' s' viene directamente de la llamada 'ToString' de' int? '. Consulte también [MSDN ToString] (http://msdn.microsoft.com/en-us/library/9hd15ket.aspx). –

2

Puede escribir algo como esto:

public delegate bool TryParser<T>(string input, out T result); 

public static bool TryParse<T> 
    (string toConvert, out T result, TryParser<T> tryParser = null) 
{ 
    if (toConvert == null) 
     throw new ArgumentNullException("toConvert"); 

    // This whole block is only if you really need 
    // it to work in a truly dynamic way. You can additionally consider 
    // memoizing the default try-parser on a per-type basis. 
    if (tryParser == null) 
    { 
     var method = typeof(T).GetMethod 
       ("TryParse", new[] { typeof(string), typeof(T).MakeByRefType() }); 

     if (method == null) 
      throw new InvalidOperationException("Type does not have a built in try-parser."); 

     tryParser = (TryParser<T>)Delegate.CreateDelegate 
      (typeof(TryParser<T>), method); 
    } 

    return tryParser(toConvert, out result); 
} 

Y luego llamar así:

int result; 
bool success = TryParse("123", out result); 

Realmente no recomendaría esto a menos que tenga algún escenario que lo requiera.

+0

Este fue un hallazgo fenomenal. Muy apreciado. – BackDoorNoBaby

Cuestiones relacionadas