web-dev-qa-db-fra.com

Méthode générique Type de retour en tant que paramètre

J'ai une méthode d'extension qui fonctionne bien pour transtyper les valeurs de chaîne en différents types, ce qui ressemble à ceci:

public static T ToType<T> (this string value, T property)
    {
        object parsedValue = default(T);
        Type type = property.GetType();

        try
        {
            parsedValue = Convert.ChangeType(value, type);
        }
        catch (ArgumentException e)
        {
            parsedValue = null;
        }

        return (T)parsedValue;
    }

Je ne suis pas satisfait de l'apparence de cette méthode lors de l'appel de la méthode:

myObject.someProperty = stringData.ToType(myObject.someProperty);

Spécifier la propriété juste pour obtenir le type de la propriété semble redondant. Je préférerais utiliser une signature comme celle-ci:

public static T ToType<T> (this string value, Type type) { ... }

et avoir T finissent par être le type de type. Cela rendrait les appels beaucoup plus propres:

myObject.someProperty = stringData.ToType(typeof(decimal));

Cependant, lorsque j'essaie d'appeler de cette façon, l'éditeur se plaint que le type de retour de la méthode d'extension ne peut pas être déduit de l'utilisation. Puis-je lier T à l'argument Type?

Qu'est-ce que je rate?

Merci

11
ZuluAlphaCharlie

Est-ce ce que vous recherchez? J'ai ajouté une prise supplémentaire pour les cas où la distribution n'est pas valide aussi

Decimal i = stringName.ToType<Decimal>();

public static T ToType<T>(this string value)
{
     object parsedValue = default(T);
     try
     {
         parsedValue = Convert.ChangeType(value, typeof(T));
     }
     catch (InvalidCastException)
     {
         parsedValue = null;
     }
     catch (ArgumentException)
     {
         parsedValue = null;
     }
     return (T)parsedValue;
} 

Modifier

une approche de raccourci pour corriger le commentaire d'Anton

if (typeof(T).IsValueType)
   return default(T);
16
Sayse

Pourquoi utiliser la propriété du tout? Modifiez simplement la manière dont vous définissez votre variable de type sur le type de votre générique.

    public static T ToType<T>(this string value)
    {
        object parsedValue = default(T);
        Type type = typeof(T);

        try
        {
            parsedValue = Convert.ChangeType(value, type);
        }
        catch (ArgumentException e)
        {
            parsedValue = null;
        }

        return (T) parsedValue;
    }

Usage:

myObject.someProperty = stringData.ToType<decimal>()
2
McAden

J'utilise ceci pour une conversion générique:

    public bool ConvertTo<T>(object from, out T to) {
        to = default(T);
        if (from is T) { to = (T)from; return true; }                                           
        Type t = typeof(T);
        //TypeConverter converter = p.converter == null ? TypeDescriptor.GetConverter(t) : p.converter;
        TypeConverter converter = TypeDescriptor.GetConverter(t);
        if ((converter != null) && (converter.CanConvertTo(t))) {
            try { to = (T)converter.ConvertTo(null, culture, from, t); return true; }
            catch { }
        }
        try { to = (T)Convert.ChangeType(from, t, culture); return true; }
        catch { }
        return false;                                                                                       
    }

    public bool ConvertTo(object from, out object to, Type type) {
        to = null;
        if (from.GetType() == type) { to = from; return true; }     
        TypeConverter converter = TypeDescriptor.GetConverter(type);
        if ((converter != null) && (converter.CanConvertTo(type))) {
            try { to = converter.ConvertTo(null, culture, from, type); return true; }
            catch { }
        }
        try { to = Convert.ChangeType(from, type, culture); return true; }
        catch { }
        return false;                                           
    }

Avant d'appeler Convert.ChangeType, ceci vérifie s'il existe une TypeConverter pour la variable donnée.

Appelez ça comme ça:

int i = 123;
string s;
if (ConvertTo<string>(i, out s) {
    // use s
}
0
joe