214 votes

TryParse générique

Je suis en train de créer une extension générique qui utilise 'TryParse" pour vérifier si une chaîne est un type donné:

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

ce ne compile pas car il ne peut pas résoudre le symbole 'TryParse'

Ce que je comprends, 'TryParse ne fait pas partie de l'interface.

Est-ce possible de le faire?

Mise à jour:

En utilisant les réponses ci-dessous je viens avec:

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

    return true;
}

Il fonctionne très bien, mais je pense que l'utilisation des exceptions dans cette façon de ne pas se sentir le droit de m'.

Update2:

Modifié pour transmettre de type plutôt que d'utiliser des génériques:

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

214voto

luke Points 6688

Vous devez utiliser la classe TypeDescriptor :

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

Bien sûr, cela provoquera une exception si la conversion échoue. Vous voudrez donc essayer de l'attraper.

85voto

Charlie Brown Points 361

J'ai également demandé un TryParse générique récemment. Voici ce que j'ai imaginé.

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

Il suffit alors d'appeler ainsi:

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

35voto

Thinking Sites Points 2513

Utiliser try / catch pour le contrôle de flux est une politique terrible. Lancer une exception entraîne des retards de performances tandis que le runtime fonctionne autour de l'exception. Validez plutôt les données avant la conversion.

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

14voto

Joseph Sturtevant Points 6597

Si vous êtes en train d'utiliser TryParse, vous pouvez utiliser la réflexion et le faire comme ceci:

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

4voto

Mark Byers Points 318575

Vous ne pouvez pas le faire sur les types généraux.

Ce que vous pouvez faire, c'est créer une interface ITryParsable et l'utiliser pour les types personnalisés qui implémentent cette interface.

Je suppose que vous avez l’intention de l’utiliser avec des types de base comme int et DateTime . Vous ne pouvez pas modifier ces types pour implémenter de nouvelles interfaces.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X