web-dev-qa-db-fra.com

Quelle est la bonne façon de vérifier les valeurs nulles?

J'adore l'opérateur de coalescence nulle, car il facilite l'attribution d'une valeur par défaut aux types nullables.

 int y = x ?? -1;

C'est super, sauf si j'ai besoin de faire quelque chose de simple avec x. Par exemple, si je veux vérifier Session, je finis généralement par devoir écrire quelque chose de plus détaillé.

J'aimerais pouvoir faire ceci:

string y = Session["key"].ToString() ?? "none";

Mais vous ne pouvez pas parce que la .ToString() est appelée avant la vérification null donc elle échoue si Session["key"] Est null. Je finis par faire ça:

string y = Session["key"] == null ? "none" : Session["key"].ToString();

Cela fonctionne et est meilleur, à mon avis, que l'alternative à trois lignes:

string y = "none";
if (Session["key"] != null)
    y = Session["key"].ToString();

Même si cela fonctionne, je suis toujours curieux de savoir s'il existe une meilleure façon. Il semble que peu importe ce que je dois toujours référencer Session["key"] Deux fois; une fois pour le chèque, et encore pour la mission. Des idées?

122
Chev

Qu'en est-il de

string y = (Session["key"] ?? "none").ToString();
183
BlackBear

Si vous le faites fréquemment en particulier avec ToString() alors vous pouvez écrire une méthode d'extension:

public static string NullPreservingToString(this object input)
{
    return input == null ? null : input.ToString();
}

...

string y = Session["key"].NullPreservingToString() ?? "none";

Ou une méthode prenant un défaut, bien sûr:

public static string ToStringOrDefault(this object input, string defaultValue)
{
    return input == null ? defaultValue : input.ToString();
}

...

string y = Session["key"].ToStringOrDefault("none");
130
Jon Skeet

Vous pouvez également utiliser as , ce qui donne null si la conversion échoue:

Session["key"] as string ?? "none"

Cela retournerait "none" même si quelqu'un a bourré un int dans Session["key"].

21
Andomar

Si ce sera toujours un string, vous pouvez lancer:

string y = (string)Session["key"] ?? "none";

Cela a l'avantage de se plaindre au lieu de cacher l'erreur si quelqu'un fourre un int ou quelque chose dans Session["key"]. ;)

14
Ry-

Toutes les solutions suggérées sont bonnes et répondent à la question; c'est juste pour l'étendre légèrement. Actuellement, la majorité des réponses ne concernent que la validation nulle et les types de chaînes. Vous pouvez étendre l'objet StateBag pour inclure une méthode générique GetValueOrDefault, similaire à la réponse publiée par Jon Skeet.

Une méthode d'extension générique simple qui accepte une chaîne comme clé, puis saisit l'objet de session. Si l'objet est nul ou n'est pas du même type, la valeur par défaut est renvoyée, sinon la valeur de session est retournée fortement typée.

Quelque chose comme ça

/// <summary>
/// Gets a value from the current session, if the type is correct and present
/// </summary>
/// <param name="key">The session key</param>
/// <param name="defaultValue">The default value</param>
/// <returns>Returns a strongly typed session object, or default value</returns>
public static T GetValueOrDefault<T>(this HttpSessionState source, string key, T defaultValue)
{
    // check if the session object exists, and is of the correct type
    object value = source[key]
    if (value == null || !(value is T))
    {
        return defaultValue;
    }

    // return the session object
    return (T)value;
}
10
Richard

Nous utilisons une méthode appelée NullOr.

Usage

// Call ToString() if it’s not null, otherwise return null
var str = myObj.NullOr(obj => obj.ToString());

// Supply default value for when it’s null
var str = myObj.NullOr(obj => obj.ToString()) ?? "none";

// Works with nullable return values, too —
// this is properly typed as “int?” (nullable int)
// even if “Count” is just int
var count = myCollection.NullOr(coll => coll.Count);

// Works with nullable input types, too
int? unsure = 47;
var sure = unsure.NullOr(i => i.ToString());

La source

/// <summary>Provides a function delegate that accepts only value types as return types.</summary>
/// <remarks>This type was introduced to make <see cref="ObjectExtensions.NullOr{TInput,TResult}(TInput,FuncStruct{TInput,TResult})"/>
/// work without clashing with <see cref="ObjectExtensions.NullOr{TInput,TResult}(TInput,FuncClass{TInput,TResult})"/>.</remarks>
public delegate TResult FuncStruct<in TInput, TResult>(TInput input) where TResult : struct;

/// <summary>Provides a function delegate that accepts only reference types as return types.</summary>
/// <remarks>This type was introduced to make <see cref="ObjectExtensions.NullOr{TInput,TResult}(TInput,FuncClass{TInput,TResult})"/>
/// work without clashing with <see cref="ObjectExtensions.NullOr{TInput,TResult}(TInput,FuncStruct{TInput,TResult})"/>.</remarks>
public delegate TResult FuncClass<in TInput, TResult>(TInput input) where TResult : class;

/// <summary>Provides extension methods that apply to all types.</summary>
public static class ObjectExtensions
{
    /// <summary>Returns null if the input is null, otherwise the result of the specified lambda when applied to the input.</summary>
    /// <typeparam name="TInput">Type of the input value.</typeparam>
    /// <typeparam name="TResult">Type of the result from the lambda.</typeparam>
    /// <param name="input">Input value to check for null.</param>
    /// <param name="lambda">Function to apply the input value to if it is not null.</param>
    public static TResult NullOr<TInput, TResult>(this TInput input, FuncClass<TInput, TResult> lambda) where TResult : class
    {
        return input == null ? null : lambda(input);
    }

    /// <summary>Returns null if the input is null, otherwise the result of the specified lambda when applied to the input.</summary>
    /// <typeparam name="TInput">Type of the input value.</typeparam>
    /// <typeparam name="TResult">Type of the result from the lambda.</typeparam>
    /// <param name="input">Input value to check for null.</param>
    /// <param name="lambda">Function to apply the input value to if it is not null.</param>
    public static TResult? NullOr<TInput, TResult>(this TInput input, Func<TInput, TResult?> lambda) where TResult : struct
    {
        return input == null ? null : lambda(input);
    }

    /// <summary>Returns null if the input is null, otherwise the result of the specified lambda when applied to the input.</summary>
    /// <typeparam name="TInput">Type of the input value.</typeparam>
    /// <typeparam name="TResult">Type of the result from the lambda.</typeparam>
    /// <param name="input">Input value to check for null.</param>
    /// <param name="lambda">Function to apply the input value to if it is not null.</param>
    public static TResult? NullOr<TInput, TResult>(this TInput input, FuncStruct<TInput, TResult> lambda) where TResult : struct
    {
        return input == null ? null : lambda(input).Nullable();
    }
}
7
Timwi

Ma préférence, pour une seule, serait d'utiliser une conversion sécurisée en chaîne au cas où l'objet stocké avec la clé n'en serait pas un. L'utilisation de ToString() peut ne pas donner les résultats souhaités.

var y = Session["key"] as string ?? "none";

Comme le dit @Jon Skeet, si vous vous retrouvez à faire beaucoup de méthode d'extension ou, mieux encore, peut-être une méthode d'extension en conjonction avec une classe SessionWrapper fortement typée. Même sans la méthode d'extension, le wrapper fortement typé peut être une bonne idée.

public class SessionWrapper
{
    private HttpSessionBase Session { get; set; }

    public SessionWrapper( HttpSessionBase session )
    {
        Session = session;
    }

    public SessionWrapper() : this( HttpContext.Current.Session ) { }

    public string Key
    {
         get { return Session["key"] as string ?? "none";
    }

    public int MaxAllowed
    {
         get { return Session["maxAllowed"] as int? ?? 10 }
    }
}

Utilisé comme

 var session = new SessionWrapper(Session);

 string key = session.Key;
 int maxAllowed = session.maxAllowed;
6
tvanfosson

créer une fonction auxiliaire

public static String GetValue( string key, string default )
{
    if ( Session[ key ] == null ) { return default; }
    return Session[ key ].toString();
}


string y = GetValue( 'key', 'none' );
3
scibuff

La réponse de Skeet est la meilleure - en particulier, je pense que sa ToStringOrNull() est assez élégante et convient le mieux à vos besoins. Je voulais ajouter une option de plus à la liste des méthodes d'extension:

Renvoie l'objet d'origine ou la valeur de chaîne par défaut pour null:

// Method:
public static object OrNullAsString(this object input, string defaultValue)
{
    if (defaultValue == null)
        throw new ArgumentNullException("defaultValue");
    return input == null ? defaultValue : input;
}

// Example:
var y = Session["key"].OrNullAsString("defaultValue");

Utilisez var pour la valeur renvoyée car elle reviendra comme type de l'entrée d'origine, uniquement comme chaîne par défaut lorsque null

2
one.beat.consumer

Il s'agit de mon petit "opérateur Elvis" sécurisé pour les versions de .NET qui ne prennent pas en charge?.

public class IsNull
{
    public static O Substitute<I,O>(I obj, Func<I,O> fn, O nullValue=default(O))
    {
        if (obj == null)
            return nullValue;
        else
            return fn(obj);
    }
}

Le premier argument est l'objet testé. La deuxième est la fonction. Et le troisième est la valeur nulle. Donc pour votre cas:

IsNull.Substitute(Session["key"],s=>s.ToString(),"none");

Il est également très utile pour les types nullables. Par exemple:

decimal? v;
...
IsNull.Substitute(v,v.Value,0);
....
0
Tomaz Stih