2009-10-31 6 views
12

code tiré de hereméthode générique TryParse Extension

Je voudrais entendre des avis d'experts sur cette méthode d'extension. Je prévois de l'utiliser, mais j'aimerais entendre parler de tout problème connu que je pourrais rencontrer. Suis-je meilleur d'utiliser sur les méthodes primaires TryParse de types?

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

Comme les réponses l'ont dit, ne pas "lancer ex". Vous * rarement *, si jamais, voulez le faire. Juste "jeter". –

+4

Il échoue également le point d'un 'Try' si vous lancez l'exception ... –

Répondre

1

Il utilise la réflexion et peut donc être lente, si la performance est un problème.

3

Les génériques sont les plus utiles lorsque vous souhaitez modifier le contrat public d'une méthode ou d'une classe, et les composants internes de la méthode ou de la classe ne se préoccupent pas vraiment du type qui varie.

Quelques exemples:

List<T> est une collection, vous pouvez mettre les choses en, et à l'intérieur de la classe ne se soucie pas (beaucoup) de ce type est que.

T System.Linq.Enumerable.First<T>(IEnumerable<T> source) renvoie le premier élément d'un groupe d'éléments. Cette méthode n'a pas besoin de savoir en interne quel type est dans le but de faire le travail. Par contre, une méthode d'analyse doit changer son comportement en fonction du type de résultat. Dans la méthode fournie, il y a Stratégie qui pousse les comportements vers d'autres méthodes, mais il y a un coût d'exécution pour ce choix.

L'alternative est de laisser l'appelant (qui doit connaître le type ou ils ne pouvaient pas appeler la méthode générique avec), choisir le convertisseur. Ce choix peut être fait au moment de la conception ou de la compilation et entraîne donc 0 coût d'exécution. Côté Note: Veuillez ne pas utiliser le pour tout relancer idiome. Tout ce qu'il fait est de réinitialiser la pile d'appels et vous ne voulez jamais faire cela.

catch (Exception ex) 
{ 
    throw ex; 
} 
+0

1 motivation pour utiliser cette méthode générique est de réduire l'appel du code client vs en utilisant des analyseurs primatifs. Vous avez raison de dire que les clients connaissent les types d'exécution, mais ils doivent également gérer les exceptions. Aussi, pouvez-vous me lier sur plus d'informations sur la réinitialisation de trace de la pile? Merci –

+0

Rethrowing lien http://msdn.microsoft.com/en-us/library/ms182363(VS.80).aspx –

+0

Et, vous pourriez obtenir le client pour vous passer l'analyseur (en tant que Func si rien d'autre) , au lieu du type - cela éviterait la réflexion. –

24

Le modèle TryParse est mieux suivant le modèle standard, ce qui permet une utilisation avec les non-struct aussi:

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

Remarque J'ai accepté un string ici, parce que c'est ce qui m'a le plus souvent signifient TryParse; sinon, Convert.ChangeType pourrait être plus approprié.

Je ne vois aucune raison pour que cela soit une méthode d'extension (comme par this dans l'exemple de la question), et certainement il est déconseillé de polluer object avec trop de méthodes d'extension.

4

Les extensions ci-dessous peuvent vous être utiles. Ils travaillent sur tout type qui a une méthode Parse ou TryParse ...

Ils viennent de ma bibliothèque d'extensions ici: http://www.codeproject.com/KB/dotnet/MBGExtensionsLibrary.aspx

Bien que ce projet est probablement un peu hors jour ... Je ll doit mettre à jour comme un certain point: -D

Espérons que cela aide!

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

Oups ... Je ne voyais pas quel âge avait le poste! LOL. Désolé pour ça. – Matt

+1

Ne soyez pas! C'était juste ce que je cherchais. Merci! – Yandros