web-dev-qa-db-fra.com

Expression C # if-null-then-null

Juste pour la curiosité/commodité: C # fournit deux fonctionnalités d'expression conditionnelle intéressantes que je connais:

string trimmed = (input == null) ? null : input.Trim();

et

string trimmed = (input ?? "").Trim();

Je manque une autre expression de ce genre pour une situation à laquelle je fais face très souvent:

Si la référence d'entrée est nulle, alors la sortie doit être nulle. Sinon, la sortie doit être le résultat de l'accès à une méthode ou une propriété de l'objet d'entrée.

C'est exactement ce que j'ai fait dans mon premier exemple, mais (input == null) ? null : input.Trim() est assez verbeux et illisible.

Y a-t-il une autre expression conditionnelle pour ce cas, ou puis-je utiliser le ?? opérateur avec élégance?

55
chiccodoro

Quelque chose comme l'opérateur de déréférencement sans danger de Groovy?

string zipCode = customer?.Address?.ZipCode;

Je suppose que l'équipe C # a examiné cela et a constaté que ce n'était pas aussi simple à concevoir avec élégance qu'on pourrait s'y attendre ... même si je n'ai pas entendu parler des détails des problèmes.

Je ne crois pas qu'il y ait une telle chose dans la langue en ce moment, je le crains ... et je n'ai pas entendu de plans pour cela, bien que cela ne signifie pas que cela ne se produira pas à un moment donné.

EDIT: Cela va maintenant faire partie de C # 6, en tant que "opérateur null-conditionnel".

48
Jon Skeet

Vous pouvez choisir entre une classe Nullify personnalisée ou une méthode d'extension NullSafe comme décrit ici: http://qualityofdata.com/2011/01/27/nullsafe-dereference-operator -en-c /

L'utilisation sera la suivante:

//Groovy:
bossName = Employee?.Supervisor?.Manager?.Boss?.Name

//C# Option 1:
bossName = Nullify.Get(Employee, e => e.Supervisor, s => s.Manager,
                       m => m.Boss, b => b.Name);
//C# Option 2:
bossName = Employee.NullSafe( e => e.Supervisor ).NullSafe( s => s.Boss )
                      .NullSafe( b => b.Name );
10
naiem

Actuellement, nous ne pouvons écrire une méthode d'extension que si vous ne voulez pas vous répéter, je le crains.

public static string NullableTrim(this string s)
{
   return s == null ? null : s.Trim();
}
9
Cheng Chen

Comme solution de contournement, vous pouvez utiliser ceci qui est basé sur Peut-être monade .

public static Tout IfNotNull<Tin, Tout>(this Tin instance, Func<Tin, Tout> Output)
{
    if (instance == null)
        return default(Tout);
    else
        return Output(instance);
}

Utilisez-le de cette façon:

int result = objectInstance.IfNotNull(r => 5);
var result = objectInstance.IfNotNull(r => r.DoSomething());
7
QrystaL

Il n'y a rien de intégré, mais vous pouvez tout récapituler dans une méthode d'extension si vous le souhaitez (bien que je ne le dérangerais probablement pas).

Pour cet exemple spécifique:

string trimmed = input.NullSafeTrim();

// ...

public static class StringExtensions
{
    public static string NullSafeTrim(this string source)
    {
        if (source == null)
            return source;    // or return an empty string if you prefer

        return source.Trim();
    }
}

Ou une version plus générale:

string trimmed = input.IfNotNull(s => s.Trim());

// ...

public static class YourExtensions
{
    public static TResult IfNotNull<TSource, TResult>(
        this TSource source, Func<TSource, TResult> func)
    {
        if (func == null)
            throw new ArgumentNullException("func");

        if (source == null)
            return source;

        return func(source);
    }
}
5
LukeH

J'ai eu le même problème, j'ai écrit quelques petites méthodes d'extension:

public static TResult WhenNotNull<T, TResult>(
    this T subject, 
    Func<T, TResult> expression)
    where T : class
{
    if (subject == null) return default(TResult);
    return expression(subject);
}

public static TResult WhenNotNull<T, TResult>(
    this T subject, Func<T, TResult> expression,
    TResult defaultValue)
    where T : class
{
    if (subject == null) return defaultValue;
    return expression(subject);
}

public static void WhenNotNull<T>(this T subject, Action<T> expression)
    where T : class
{
    if (subject != null)
    {
        expression(subject);
    }
}

Vous l'utilisez comme ceci;

string str = null;
return str.WhenNotNull(x => x.Length);

ou

IEnumerable<object> list;
return list.FirstOrDefault().WhenNotNull(x => x.id, -1);

ou

object obj;
IOptionalStuff optional = obj as IOptionalStuff;
optional.WhenNotNull(x => x.Do());

Il existe également des surcharges pour les types nullables.

4
Stefan Steinegger