50 votes

Comment puis-je résoudre ce problème pour effectuer une conversion générique en Nullable <T> ?

J'utilise actuellement cette pratique de conversion de la méthode d'extension pour faire des conversions entre types:

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

Cependant, il n'est pas comme la conversion de valeurs valides pour Nullable, par exemple, d'échec:

    "1".To<int?>();

Évidemment, 1 est facilement converti en une (int?), mais il obtient l'erreur:

    Invalid cast from 'System.String' to 'System.Nullable`1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'.

C'est évidemment un exemple simplifié, en réalité, je suis de l'utiliser pour faire des conversions de types de chaînes comme suit:

packageDb.Quantity = package.package.ElementDeep(Namespace + "PackageQuantity", Namespace + "ActualQuantity", Namespace + "Quantity").ValueOrNull().To<int?>();

Si Convertir.ChangeType n'aime pas les valeurs null, n'importe qui ont des idées géniales?

104voto

LukeH Points 110965
public static T To<T>(this IConvertible obj)
{
    Type t = typeof(T);
    Type u = Nullable.GetUnderlyingType(t);

    if (u != null)
    {
        if (obj == null)
            return default(T);

        return (T)Convert.ChangeType(obj, u);
    }
    else
    {
        return (T)Convert.ChangeType(obj, t);
    }
}

5voto

Henrique Points 63
 public static T To<T>(this IConvertible obj) 
{
    Type t = typeof(T);
    if (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>))
    	t = t.GetGenericArguments()[0];

    return (T)Convert.ChangeType(obj, t); 
}
 

Mais si la conversion échoue, il lève une exception, ne renvoyant pas une valeur null comme prévu.

3voto

Nick Strupat Points 1778

J'ai fini avec ça

 private static T To<T>(this Object @object, Boolean returnDefaultOnException)
{
    Type type = typeof(T);
    Type underlyingTypeOfNullable = Nullable.GetUnderlyingType(type);
    try
    {
        return (T) Convert.ChangeType(@object, underlyingTypeOfNullable ?? type);
    }
    catch (Exception exception)
    {
        if (returnDefaultOnException)
            return default(T);
        String typeName = type.Name;
        if (underlyingTypeOfNullable != null)
            typeName += " of " + underlyingTypeOfNullable.Name;
        throw new InvalidCastException("Object can't be cast to " + typeName, exception);

    }
}
public static T To<T>(this Object @object) { return @object.To<T>(returnDefaultOnException: false); }
public static T ToOrDefault<T>(this Object @object) { return @object.To<T>(returnDefaultOnException: true); }
 

Il se comporte comme les méthodes d'extension LINQ Single et SingleOrDefault et First et FirstOrDefault .

En bref, To<T>() tente de convertir et renvoie en cas d'échec, tandis que ToOrDefault<T>() tente de convertir et renvoie default(T) en cas d'échec.

3voto

Adam Robinson Points 88472

Peut-être que je suis à côté de la question, mais dans l'instance de Nullable, comment est-ce que votre méthode soit la lisibilité, de la performance ou de la maintenance avantage par rapport à une distribution simple, comme (int?)1 ?

A côté de cela, peut-être une autre méthode d'extension?

public static T? ToNullable<T>(this T obj) where T:struct
{
    return (T?)obj;
}

Modifier

Après examen de votre edit, pourquoi la fonction générique que j'ai fourni ne fonctionne pas comme un substitut à votre To<T> fonction dans cette ligne de code? Vous ne pouvez pas permettre une conversion à Nullable pour tout type (c'est pourquoi ChangeType ne fonctionne pas) parce que générique accepte uniquement les types de valeur. Vous devrez utiliser une fonction comme celle que j'ai fourni ou modifier votre signature d' To<T> pour n'accepter que les types valeur et ajouter un cas particulier pour Nullable<T>.

2voto

Eugenio Miró Points 1136

La solution de Luke était bonne pour moi (et a évidemment obtenu son vote positif) mais je l'ai simplifiée pour moi de cette façon

     private static Type ResolveType(String typeName)
    {
        Type t = Type.GetType(typeName);
        if (t == null)
            return null;

        Type u = Nullable.GetUnderlyingType(t);

        if (u != null) {
            t = u;
        }
        return t;
    }
 

parce que je suis parti d'une chaîne pas d'un type ... pensées?

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