Unique ways to use the null coalescing operator
Solution 1
Well, first of all, it's much easier to chain than the standard ternary operator:
string anybody = parm1 ?? localDefault ?? globalDefault;
vs.
string anyboby = (parm1 != null) ? parm1
: ((localDefault != null) ? localDefault
: globalDefault);
It also works well if a null-possible object isn't a variable:
string anybody = Parameters["Name"]
?? Settings["Name"]
?? GlobalSetting["Name"];
vs.
string anybody = (Parameters["Name"] != null ? Parameters["Name"]
: (Settings["Name"] != null) ? Settings["Name"]
: GlobalSetting["Name"];
Solution 2
I've used it as a lazy load one-liner:
public MyClass LazyProp
{
get { return lazyField ?? (lazyField = new MyClass()); }
}
Readable? Decide for yourself.
Solution 3
I've found it useful in two "slightly odd" ways:
- As an alternative for having an
out
parameter when writingTryParse
routines (i.e. return the null value if parsing fails) - As a "don't know" representation for comparisons
The latter needs a little bit more information. Typically when you create a comparison with multiple elements, you need to see whether the first part of the comparison (e.g. age) gives a definitive answer, then the next part (e.g. name) only if the first part didn't help. Using the null coalescing operator means you can write pretty simple comparisons (whether for ordering or equality). For example, using a couple of helper classes in MiscUtil:
public int Compare(Person p1, Person p2)
{
return PartialComparer.Compare(p1.Age, p2.Age)
?? PartialComparer.Compare(p1.Name, p2.Name)
?? PartialComparer.Compare(p1.Salary, p2.Salary)
?? 0;
}
Admittedly I now have ProjectionComparer in MiscUtil, along with some extensions, which make this kind of thing even easier - but it's still neat.
The same can be done for checking for reference equality (or nullity) at the start of implementing Equals.
Solution 4
Another advantage is that the ternary operator requires a double evaluation or a temporary variable.
Consider this, for instance:
string result = MyMethod() ?? "default value";
while with the ternary operator you are left with either:
string result = (MyMethod () != null ? MyMethod () : "default value");
which calls MyMethod twice, or:
string methodResult = MyMethod ();
string result = (methodResult != null ? methodResult : "default value");
Either way, the null coalescing operator is cleaner and, I guess, more efficient.
Solution 5
Another thing to consider is that the coalesce operator doesn't call the get method of a property twice, as the ternary does.
So there are scenarios where you shouldn't use the ternary operator, for example:
public class A
{
var count = 0;
private int? _prop = null;
public int? Prop
{
get
{
++count;
return _prop
}
set
{
_prop = value;
}
}
}
If you use:
var a = new A();
var b = a.Prop == null ? 0 : a.Prop;
the getter will be called twice and the count
variable will be equal to 2, and if you use:
var b = a.Prop ?? 0
the count
variable will be equal to 1, as it should.
Related videos on Youtube
Armstrongest
Front end work, Back end work. Cool kids call it the full stack. Ever curious developer of fine web stuff on the internets. "You can't work on the web and not be strive for polyglotism."
Updated on November 14, 2020Comments
-
Armstrongest over 3 years
I know the standard way of using the null coalescing operator in C# is to set default values.
string nobody = null; string somebody = "Bob Saget"; string anybody = ""; anybody = nobody ?? "Mr. T"; // Returns Mr. T anybody = somebody ?? "Mr. T"; // Returns "Bob Saget"
But what else can
??
be used for? It doesn't seem as useful as the ternary operator, apart from being more concise and easier to read than:nobody = null; anybody = nobody == null ? "Bob Saget" : nobody; // Returns Bob Saget
So given that fewer even know about null coalescing operator...
-
Have you used
??
for something else? -
Is
??
necessary, or should you just use the ternary operator (that most are familiar with)
-
-
Godeke over 15 yearsHmmm, you found a counterexample to "why would someone want to use it as an obfuscated IF"... that is actually very readable to me.
-
chakrit over 15 yearsThe chaining is a big plus for the operator, removes a bunch of redundant IFs
-
Armstrongest over 15 yearsInteresting. You're using "this" as a property. I've never done that.
-
Matt Hamilton over 15 yearsYeah, it's part of how IDataErrorInfo works. Generally that syntax is only useful on collection classes.
-
Armstrongest about 15 yearsYou can do this with Extension methods, but I agree, it would be a nice addition to the code and very useful in a web context.
-
Max Galkin almost 15 yearsYeah, this is a frequent scenario... there is even a special method String.IsNullOrEmpty(string)...
-
Beweelam almost 15 yearsI like what you did with the PartialComparer, but was looking for cases where I need to keep the evaluated expression variables. I am not versed in lambdas and extensions, so could you see if the following adheres to a similar pattern (i.e. does it work)? stackoverflow.com/questions/1234263/#1241780
-
Chris Marisic about 14 yearsThis my primary usage of the Null Coalescing.
-
Justin K almost 14 yearsI might be missing something (I mostly use Java), but isn't there a race condition there?
-
Jeffrey L Whitledge almost 14 years@Justin K - There is only a race condition if multiple threads are accessing the LazyProp property of the same object. It's easily fixable with a lock, if thread safty of each instance is required. Clearly in this example, it is not required.
-
Justin K almost 14 years@Jeffrey: If it were clear, I wouldn't have asked the question. :) When I saw that example, I immediately thought of a singleton member, and since I happen to do most of my coding in a multithreaded environment... But, yeah, if we assume the code is correct, anything extra is unnecessary.
-
user over 13 years+1. This is one big reason why I like the null coalescing operator. It's particularly useful when calling
MyMethod()
has any sort of side effects. -
JAB almost 13 years"the null-coalesce operator doesn't detect empty strings." Well it is the null -coalescing operator, not the nullOrEmpty -coalescing operator. And personally, I despise mixing null and empty values in languages that distinguish between the two, which makes interfacing with things that don't quite annoying. And I'm a bit obsessive-compulsive, so it annoys me when languages/implementations don't distinguish between the two anyway, even if I understand the reasoning why (like in [most implementations of?] SQL).
-
Kit almost 12 years
??
can't be overloaded: msdn.microsoft.com/en-us/library/8edha89s(v=vs.100).aspx -- that would be a great one to have overloadable though. I use a combination:s1.Nullify() ?? s2.Nullify()
wherestring Nullify(this s)
returns anull
in cases when the string is empty. -
TinyTimZamboni over 11 yearsIf
MyMethod()
does not have any effects outside of returning a value, the compiler knows not to call it twice, so you really don't have to worry about efficiency here in the majority of cases. -
xdhmoore about 11 yearsIt is also keeps things more readable IMHO when
MyMethod()
is a chained sequence of dotted objects. Ex:myObject.getThing().getSecondThing().getThirdThing()
-
Niall Connaughton almost 11 yearsIt doesn't have to be a Singleton to have a race condition. Just a shared instance of the class that contains LazyProp, and multiple threads that access LazyProp. Lazy<T> is a better way to do this kind of thing, and is threadsafe by default (you can elect to modift the threadsafety of Lazy<T>).
-
causa prima over 10 yearsThe only problem? I just found myself wanting ??= and found this thread while seeing if there was a way to do it. (Situation: The first pass loaded the exception cases, now I want to go back through and load default values into anything that didn't already get loaded.)
-
CompuChip over 10 yearsI may be a bit late here, but that second example will throw if
kvp == null
. And actuallyNullable<T>
has aGetValueOrDefault
method that I normally use. -
Ryan over 10 yearsKeyValuePair is a value type in the .NET framework, so accessing any of its properties would never throw a null reference exception. msdn.microsoft.com/en-us/library/5tbh8a42(v=vs.110).aspx
-
Andrew almost 9 yearsYou are storing error messages in
this["Name"]
,this["Address"]
, etc?? -
Kuba Wyrostek over 8 yearsThis deserves more upvotes. I've read sooo many times that
??
is equivalent to?:
. -
Kuba Wyrostek over 8 years@TinyTimZamboni, do you have a reference for this behavior of compiler?
-
TinyTimZamboni over 8 years@KubaWyrostek I don't have knowledge of the specific workings of the C# compiler, but I have some experience with static compiler theory with llvm. There's a number of approaches a compiler can take to optimize a call like this. Global Value Numbering will notice that the two calls to
MyMethod
are identical in this context, assuming thatMyMethod
is a Pure function. Another option is Automatic Memoization or just having the function close in cache. On the other hand: en.wikipedia.org/wiki/Global_value_numbering -
Kuba Wyrostek over 8 yearsMSDN on C# states that both condition and winning value are evaluated so I was wondering if C# specification follows this statement. To me this is not just a question of optimization. Two calls to
MyMethod()
are not thread-safe: returned value can differ between calls although the method has no side effects itself. -
David A. Gray about 7 yearsI just used it today to replace a simple IF block that I wrote before I knew about either ternary or null coalescing operator. The true and false branches of the original IF statement called the same method, replacing one of its arguments with a different value if a certain input is NULL. With the null coalescing operator, it's one call. This is really powerful when you have a method that needs two or more such substitutions!
-
arichards over 6 yearsResharper will actually suggest this as a refactor for a "traditional" lazy load.
-
Linas almost 6 yearsValid point about a getter being called twice. But this example I would consider a bad design patter to have such misleadingly named getter to actually make changes to the object.
-
Steve Kidd almost 6 yearsVery late comment from me - but pleased to see somebody cover that a ternary operator is an operator with three arguments (of which there is now more than one in C#).
-
Jesse de Wit about 5 yearsWouldn't it be great if this line could be written as
arg ?= Arg.Default
?