Existe-t-il une fonction Parse () générique qui convertira une chaîne en n'importe quel type à l'aide de parse?

91

Je souhaite convertir une chaîne en un type générique comme intou dateou longbasé sur le type de retour générique.

En gros, une fonction comme Parse<T>(String)celle-ci renvoie un élément de type T.

Par exemple, si un int a été passé, la fonction doit le faire en int.parseinterne.

Karim
la source

Réponses:

132

System.Convert.ChangeType

Selon votre exemple, vous pourriez faire:

int i = (int)Convert.ChangeType("123", typeof(int));
DateTime dt = (DateTime)Convert.ChangeType("2009/12/12", typeof(DateTime));

Pour satisfaire votre exigence de "type de retour générique", vous pouvez écrire votre propre méthode d'extension:

public static T ChangeType<T>(this object obj)
{
    return (T)Convert.ChangeType(obj, typeof(T));
}

Cela vous permettra de faire:

int i = "123".ChangeType<int>();
Ani
la source
cool, mais la chose étrange s'appelle ChangeType, donc je penserais que cette fonction fait une sorte de distribution et non d'analyse
Karim
7
MSDN dit qu'il s'agit simplement d'un wrapper qui trouve la bonne méthode de conversion sur l'objet source, exigeant qu'il implémente l'interface IConvertible.
Ani
S'il doit être implémenté IConvertable, ne devriez-vous pas également contraindre le T, c'est T ChangeType<T>(this object obj) where T : IConvertable-à- dire ?
Liam
2
@Liam: Non, ça objdoit être IConvertible, mais il n'y a aucun moyen de le spécifier au moment de la compilation.
Ani
si j'ai besoin de quelque chose comme TryChangeType qui renvoie null ou false en cas d'échec? Seulement en attrapant l'exception?
Hopeless
22

Eh bien, on dirait que je suis trop tard pour répondre sur ce fil. Mais voici ma mise en œuvre:

Fondamentalement, j'ai créé une méthode Extention pour la classe Object. Il gère tous les types, c'est-à-dire nullable, classes et struct.

 public static T ConvertTo<T>(this object value)
           {
               T returnValue;

               if (value is T variable)
                   returnValue = variable;
               else
                   try
                   {
                       //Handling Nullable types i.e, int?, double?, bool? .. etc
                       if (Nullable.GetUnderlyingType(typeof(T)) != null)
                       {
                           TypeConverter conv = TypeDescriptor.GetConverter(typeof(T));
                           returnValue = (T) conv.ConvertFrom(value);
                       }
                       else
                       {
                           returnValue = (T) Convert.ChangeType(value, typeof(T));
                       }
                   }
                   catch (Exception)
                   {
                       returnValue = default(T);
                   }

               return returnValue;
           }
Pranay Deep
la source
À mon humble avis, c'est la meilleure réponse car elle contient également le "nullable" -aspect
Ole Albers
y a-t-il une raison spécifique pour laquelle vous utilisez TypeDescriptorpour les types Nullable et Convert.ChangeTypepour les non Nullables? Ce trybloc entier peut être réduit à seulement TypeConverter2 lignes de code et il fonctionnera pour les deux, nullable et non nullable.
IMujagic le
8

version plus propre de la réponse de Pranay

public static T ConvertTo<T>(this object value)
{
    if (value is T variable) return variable;

    try
    {
        //Handling Nullable types i.e, int?, double?, bool? .. etc
        if (Nullable.GetUnderlyingType(typeof(T)) != null)
        {
            return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(value);
        }

        return (T)Convert.ChangeType(value, typeof(T));
    }
    catch (Exception)
    {
        return default(T);
    }
}
Eonasdan
la source
0

Il existe quelques conventions dans le .NET pour convertir des objets d'un type à un autre.

Mais ces méthodes sont beaucoup plus lentes que vos méthodes habituelles T.Parse(string), provoquent une boxe et impliquent de nombreuses allocations à chaque fois que vous souhaitez convertir une valeur unique.

Pour ValueString , j'ai choisi de trouver une méthode d'analyse statique appropriée du type utilisant la réflexion, de créer une expression lambda en l'appelant et de mettre en cache le délégué compilé pour une utilisation future (voir cette réponse pour un exemple).

Il revient également aux méthodes que j'ai mentionnées ci-dessus si le type n'a pas de méthode d'analyse appropriée (voir la section sur les performances dans le readme).

var v = new ValueString("15"); // struct
var i = v.As<int>(); // Calls int.Parse.
Şafak Gür
la source