web-dev-qa-db-fra.com

Cast objet en décimal? (décimal annulable)

Si vous avez ceci dans le setter d'une propriété:

decimal? temp = value as decimal?;

valeur = "90"

Mais après le casting, temp est null ...

Quelle est la bonne façon de faire ce casting?

31
Natrium

Le déballage ne fonctionne que si le type est identique! Vous ne pouvez pas décompresser un object qui ne contient pas la valeur cible. Ce dont vous avez besoin, c'est de

decimal tmpvalue;
decimal? result = decimal.TryParse((string)value, out tmpvalue) ?
                  tmpvalue : (decimal?)null;

Cela vérifie si la valeur est analysable en tant que decimal. Si oui, affectez-le à result; sinon affectez null. Le code suivant fait à peu près la même chose et pourrait être plus facile à comprendre pour les personnes qui ne connaissent pas l'opérateur conditionnel ?::

decimal tmpvalue;
decimal? result = null;
if (decimal.TryParse((string)value, out tmpvalue))
    result = tmpvalue;
67
Konrad Rudolph

vous devez analyser la décimale. Mais si vous voulez que votre décimal soit nul lorsque la chaîne n'est pas correcte, utilisez TryParse:

decimal parsedValue;
decimal? temp = decimal.TryParse(value, out parsedValue)
                ? value
                : (decimal?)null;

De cette façon, vous éviterez les exceptions lors de l'analyse des chaînes mal formées.

Presque tous les types primitifs fournissent des méthodes Parse et TryParse pour convertir à partir d'une chaîne.

Il est également recommandé de passer une culture pour l'argument fournisseur à la méthode pour éviter les problèmes avec le séparateur décimal. Si vous lisez à partir d'un autre système, CultureInfo.InvariantCulture est probablement le chemin à parcourir (mais ce n'est pas la valeur par défaut).

bool TryParse(string s, NumberStyles style,
  IFormatProvider provider, out decimal result)
5
thinkbeforecoding

et si vous utilisez decimal? temp = (decimal?)value;

2
StevenMcD

Si vous ne souhaitez pas analyser les chaînes, mais souhaitez vous assurer que vous recevez null, decimal ou nullable decimal, vous pouvez faire quelque chose comme ceci:

public static Nullable<T> Convert<T>(object input) 
    where T : struct
{
    if (input == null)
        return null;
    if (input is Nullable<T> || input is T)
        return (Nullable<T>)input;
    throw new InvalidCastException();
}

Vous pouvez le faire renvoyer null sur la dernière ligne si vous souhaitez éviter les exceptions, bien que cela ne fasse pas de distinction entre les valeurs null réelles et les transtypages incorrects.

Notez que vous devez utiliser l'opérateur "is", car l'opérateur "as" ne fonctionne pas sur les types de valeur et la conversion sans vérification peut générer une exception InvalidCastException.

Vous pouvez également en faire une méthode d'extension:

public static class ObjectExtensions
{
    public static Nullable<T> ToNullable<T>(this object input)
        where T : struct
    {
        if (input == null)
            return null;
        if (input is Nullable<T> || input is T)
            return (Nullable<T>)input;
        throw new InvalidCastException();
    }
}

Et utilisez-le comme ceci:

object value = 123.45m;
decimal? dec = value.ToNullable<decimal>();

Cela aidera à éviter les avertissements de contrat de code concernant le déballage des références nulles.

2
Stephen Drew