127 votes

Appel de méthode si non nul en C #

Est-il possible en quelque sorte de raccourcir cette déclaration?

 if (obj != null)
    obj.SomeMethod();
 

parce que j’écris souvent cela et que cela devient assez énervant. La seule chose à laquelle je peux penser est d'implémenter le motif Null Object , mais ce n'est pas ce que je peux faire à chaque fois et ce n'est certainement pas une solution pour raccourcir la syntaxe.

Et problème similaire avec les événements, où

 public event Func<string> MyEvent;
 

puis invoquer

 if (MyEvent != null)
    MyEvent.Invoke();
 

195voto

Marc Gravell Points 482669

Non, il n'y a pas de magie null-safe, à une exception près; méthodes d'extension - par exemple:

 public static void SafeInvoke(this Action action) {
    if(action != null) action();
}
 

maintenant c'est valide:

 Action act = null;
act.SafeInvoke(); // does nothing
act = delegate {Console.WriteLine("hi");}
act.SafeInvoke(); // writes "hi"
 

Dans le cas d'événements, cela a l'avantage de supprimer également la condition de concurrence, c'est-à-dire que vous n'avez pas besoin d'une variable temporaire. Donc normalement vous auriez besoin de:

 var handler = SomeEvent;
if(handler != null) handler(this, EventArgs.Empty);
 

mais avec:

 public static void SafeInvoke(this EventHandler handler, object sender) {
    if(handler != null) handler(sender, EventArgs.Empty);
}
 

nous pouvons utiliser simplement:

 SomeEvent.SafeInvoke(this); // no race condition, no null risk
 

10voto

19kt4 Points 833

Une méthode d'extension rapide:

     public static void IfNotNull<T>(this T obj, Action<T> action, Action actionIfNull = null) where T : class {
        if(obj != null) {
            action(obj);
        } else if ( actionIfNull != null ) {
            actionIfNull();
        }
    }
 

Exemple:

   string str = null;
  str.IfNotNull(s => Console.Write(s.Length));
  str.IfNotNull(s => Console.Write(s.Length), () => Console.Write("null"));
 

Ou bien:

     public static TR IfNotNull<T, TR>(this T obj, Func<T, TR> func, Func<TR> ifNull = null) where T : class {
        return obj != null ? func(obj) : (ifNull != null ? ifNull() : default(TR));
    }
 

Exemple:

     string str = null;
    Console.Write(str.IfNotNull(s => s.Length.ToString());
    Console.Write(str.IfNotNull(s => s.Length.ToString(), () =>  "null"));
 

4voto

Sven Künzler Points 935

Les événements peuvent être initialisée avec un vide par défaut délégué qui n'est jamais supprimée:

public event EventHandler MyEvent = delegate { };

Pas de nulle-la vérification nécessaire.

[Mise à jour, grâce à Bevan pour signaler]

Être conscient de la possibilité d'impact sur les performances, si. Un rapide micro point de référence, je n'indique que le traitement d'un événement avec pas d'abonnés est de 2 à 3 fois plus lent lorsque vous utilisez le "défaut de délégué" modèle. (Sur mon dual core 2,5 GHz ordinateur portable qui signifie 279ms : 785ms pour la levée de 50 millions de non-abonné événements.). Pour l'application des points chauds, qui pourrait être un problème à considérer.

2voto

Darrel Miller Points 56797

Cet article de Ian Griffiths propose deux solutions différentes au problème qui, conclut-il, sont des astuces intéressantes que vous ne devriez pas utiliser.

2voto

andrey.tsykunov Points 1266

Cerating de l'extension de la méthode comme celle proposée ne résout pas vraiment les problèmes avec des conditions de course, mais plutôt de le cacher.

public static void SafeInvoke(this EventHandler handler, object sender)
{
    if (handler != null) handler(sender, EventArgs.Empty);
}

Comme l'a déclaré ce code est l'élégant équivalent à la solution avec la variable temporaire, mais...

Le problème avec la fois que c'est possible que subsciber de l'événement pourrait être appelée APRÈS qu'il a désabonné de l'événement. Cela est possible parce que le désabonnement peut se produire après l'instance de délégué est copié dans la variable temp (ou transmise en tant que paramètre à la méthode ci-dessus), mais devant le délégué est invoquée.

En général, le comportement du code du client est imprévisible dans ce cas: état des composants ne pouvait pas permettre de manipuler la notification d'événements déjà. Il est possible d'écrire un code client dans la façon de le gérer, mais il serait mis unnecesssary la responsabilité du client.

La seule façon connue d'assurer fil safity est l'utilisation de lock déclaration de l'expéditeur de l'événement. Cela garantit que tous les abonnements\désinscriptions\invocation sont sérialisés.

Pour être plus précis verrouillage doit être appliquée de la même synchronisation de l'objet utilisé dans ajout / suppression de l'événement méthodes accesseur qui est la valeur par défaut 'cette'.

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