Method call if not null in C#

C#Null

C# Problem Overview


Is it possible to somehow shorten this statement?

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

because I happen to write this a lot and it gets pretty annoying. The only thing I can think of is to implement Null Object pattern, but that's not what I can do every time and it's certainly not a solution to shorten syntax.

And similar problem with events, where

public event Func<string> MyEvent;

and then invoke

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

C# Solutions


Solution 1 - C#

From C# 6 onwards, you can just use:

MyEvent?.Invoke();

or:

obj?.SomeMethod();

The ?. is the null-propagating operator, and will cause the .Invoke() to be short-circuited when the operand is null. The operand is only accessed once, so there is no risk of the "value changes between check and invoke" problem.

===

Prior to C# 6, no: there is no null-safe magic, with one exception; extension methods - for example:

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

now this is valid:

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

In the case of events, this has the advantage of also removing the race-condition, i.e. you don't need a temporary variable. So normally you'd need:

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

but with:

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

we can use simply:

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

Solution 2 - C#

What you're looking for is the Null-Conditional (not "coalescing") operator: ?.. It's available as of C# 6.

Your example would be obj?.SomeMethod();. If obj is null, nothing happens. When the method has arguments, e.g. obj?.SomeMethod(new Foo(), GetBar()); the arguments are not evaluated if obj is null, which matters if evaluating the arguments would have side effects.

And chaining is possible: myObject?.Items?[0]?.DoSomething()

Solution 3 - C#

A quick extension method:

    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();
        }
    }

example:

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

or alternatively:

    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));
    }

example:

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

Solution 4 - C#

Events can be initialized with an empty default delegate which is never removed:

public event EventHandler MyEvent = delegate { };

No null-checking necessary.

[Update, thanks to Bevan for pointing this out]

Be aware of the possible performance impact, though. A quick micro benchmark I did indicates that handling an event with no subscribers is 2-3 times slower when using the the "default delegate" pattern. (On my dual core 2.5GHz laptop that means 279ms : 785ms for raising 50 million not-subscribed events.). For application hot spots, that might be an issue to consider.

Solution 5 - C#

Yes, in C# 6.0 -- https://msdn.microsoft.com/en-us/magazine/dn802602.aspx.

object?.SomeMethod()

Solution 6 - C#

This article by Ian Griffiths gives two different solutions to the problem that he concludes are neat tricks that you should not use.

Solution 7 - C#

Cerating extention method like one suggested does not really solve issues with race conditions, but rather hide them.

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

As stated this code is the elegant equivalent to solution with temporary variable, but...

The problem with both that it's possible that subsciber of the event could be called AFTER it has unsubscribed from the event. This is possible because unsubscription can happen after delegate instance is copied to the temp variable (or passed as parameter in the method above), but before delegate is invoked.

In general the behaviour of the client code is unpredictable in such case: component state could not allow to handle event notification already. It's possible to write client code in the way to handle it, but it would put unnecesssary responsibility to the client.

The only known way to ensure thread safity is to use lock statement for the sender of the event. This ensures that all subscriptions\unsubscriptions\invocation are serialized.

To be more accurate lock should be applied to the same sync object used in add\remove event accessor methods which is be default 'this'.

Solution 8 - C#

I agree with the answer by Kenny Eliasson. Go with Extension methods. Here is a brief overview of extension methods and your required IfNotNull method.

Extension Methods ( IfNotNull method )

Solution 9 - C#

Maybe not better but in my opinion more readable is to create an extension method

public static bool IsNull(this object obj) {
 return obj == null;
}

Solution 10 - C#

I have made this generic extension that I use.

public static class ObjectExtensions {
    public static void With<T>(this T value, Action<T> todo) {
        if (value != null) todo(value);
    }
}

Then I use it like below.

string myString = null;
myString.With((value) => Console.WriteLine(value)); // writes nothing
myString = "my value";
myString.With((value) => Console.WriteLine(value)); // Writes `my value`

Solution 11 - C#

There is a little-known null operator in C# for this, ??. May be helpful:

http://weblogs.asp.net/scottgu/archive/2007/09/20/the-new-c-null-coalescing-operator-and-using-it-with-linq.aspx

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJakub ArnoldView Question on Stackoverflow
Solution 1 - C#Marc GravellView Answer on Stackoverflow
Solution 2 - C#VimesView Answer on Stackoverflow
Solution 3 - C#katbyteView Answer on Stackoverflow
Solution 4 - C#Sven KünzlerView Answer on Stackoverflow
Solution 5 - C#epylarView Answer on Stackoverflow
Solution 6 - C#Darrel MillerView Answer on Stackoverflow
Solution 7 - C#andrey.tsykunovView Answer on Stackoverflow
Solution 8 - C#RohitView Answer on Stackoverflow
Solution 9 - C#Kenny EliassonView Answer on Stackoverflow
Solution 10 - C#TrenskowView Answer on Stackoverflow
Solution 11 - C#Matt ShermanView Answer on Stackoverflow