Test with if (x is null) or if (x is not null). Supply a default with x ?? fallback, and reach through something that may be null with x?.Name, which gives null instead of throwing. For an int?, use value ?? 0 or value.HasValue to get a plain int. Calling a member on a null reference is what throws NullReferenceException: "Object reference not set to an instance of an object."
C# has two kinds of null. Reference types such as string, arrays, lists and your own classes can hold null, and any member access on one throws. Value types such as int, bool and DateTime can't, unless you make them nullable with ?, as in int?. The language has grown an operator for each job: is null to test, ?? and ??= for defaults, ?. and ?[] to skip the rest of an expression, plus nullable reference types to catch mistakes at compile time. Each example runs on this page: hit Run, then edit the code and run it again.
1is null and is not nullRecommended
x is null (C# 7) and x is not null (C# 9) are the idiomatic checks. For everyday types they agree with x == null and x != null, but they mean something stricter: is null is a pattern that asks whether the reference really is null, while == calls whatever operator == the type defines. Patterns also check and unwrap in one step, so is { } text gives you a non-null variable to use.
Output
Prints is null and True; the is not null line prints nothing. The Widget rows are the reason to prefer the pattern: its overloaded == says the placeholder equals null, so == null prints True for an object that exists, while is null and ReferenceEquals both print False. Unity's UnityEngine.Object overloads == the same way for destroyed objects, which is why Unity code uses == on purpose. The pattern lines print an int: 43, 5 chars and not null and longer than 3: a property pattern such as { Length: > 3 } only matches a non-null value.
2Default values with ?? and ??=
The null-coalescing operator a ?? b returns a unless it is null, and then returns b. It evaluates a once and only evaluates b when it needs to, so it replaces a != null ? a : b. Chain it to take the first non-null value from several sources. x ??= value (C# 8) assigns only when x is null, which is the shortest lazy initialization there is.
Output
Prints Guest, Ada Lovelace and config.json. The list line is 1: first: the second ??= saw a list that already existed and left it alone. Then [], the trap: ?? only looks for null, so an empty string passes straight through. Use string.IsNullOrWhiteSpace when blank should count as missing, which gives [Guest]. The last line shows ?? throw, a one-line guard that prints ArgumentNullException: Value cannot be null. (Parameter 'value').
3Skip members on null with ?. and ?[]
The null-conditional operator a?.B (C# 6) reads B only when a isn't null. Otherwise the whole rest of the chain is skipped and the result is null, so customer?.Address?.City never throws. Put ?? on the end to turn that null into a default. a?[i] does the same for indexers, and handler?.Invoke(...) is the standard way to raise an event or call a delegate that may have no subscribers.
Output
The chains print London, then (no city) twice: once because the address is null, once because the customer is. A value-type member comes back nullable, so nobody?.Name.Length is an int? (True for is null), and ?? 0 turns it back into an int, here 5. The method lines show that the skip includes the arguments: for nobody it prints (skipped) and Loud never runs, while the real customer prints evaluating argument and HI, Ada. Then (no tags), and saved: report.pdf only once a handler is attached. C# 14 also allows ?. on the left of an assignment, but this page's compiler rejects that form, so write if (c is not null) c.Address = a; here.
4int? and converting it to int
A plain int can't be null; int?, short for Nullable<int>, can. It is the type for a database column that allows NULL, an optional setting or a parse that may fail. HasValue tells you whether there is a number, and you can't pass an int? where an int is expected without deciding what null becomes: ?? 0, GetValueOrDefault(), or .Value after a check.
Output
Prints False, True, True, then 0 0 -1 25 for the four conversions and price is 25. Casting a null int? to int, or reading .Value, throws InvalidOperationException: Nullable object must have a value. Arithmetic on a null gives null rather than an error, so price + stock is null (True) and prints as an empty string, []. Comparisons are stranger: stock > 0 and stock <= 0 are both False, while stock == null is True. The int.TryParse helper prints 42 and -1, a common way to get an int? from text.
5Fix a NullReferenceException
NullReferenceException means a member was used on a reference that was null: a method call, a property, an indexer or a field. The message never says which one, so read the stack trace for the line, then ask where each reference on that line comes from. The usual sources are an array or field nobody assigned, a lookup such as FirstOrDefault that found nothing, and an as cast to the wrong type.
Output
All four lines print the same message, Object reference not set to an instance of an object., which is why the stack trace matters more than the text. The fixes print 0, not a string and 0: handle the empty lookup with ?. and ??, use a type pattern instead of as, and initialize fields. ArgumentNullException.ThrowIfNull fails at the method that received the null, with the parameter name: Value cannot be null. (Parameter 'name'). Nullable reference types (on by default in projects created since .NET 6, or #nullable enable) turn most of these into compiler warnings before the code runs: a string must not be null, a string? may be, and dereferencing the result of FirstOrDefault or as without a check is flagged as CS8602. Array elements are a known blind spot. This page shows only the program's output, not compiler warnings, so build locally to see them.
6Which should you use?
| Method | Gives you | Since | Best for |
|---|---|---|---|
| x is null / x is not null | bool, ignores overloaded == | C# 7 / C# 9 | Any null test: the default |
| x == null | bool, uses the type's operator == | C# 1 | Older code, Unity objects |
| x ?? fallback | x, or the fallback if null | C# 2 | Defaults, int? to int, ?? throw guards |
| x ??= value | Assigns only if null | C# 8 | Lazy initialization |
| x?.Member / x?[i] | The member, or null | C# 6 | Chains, events, optional objects |
| string.IsNullOrWhiteSpace(s) | true for null, "" and spaces | .NET 4 | User input where blank means missing |
| ArgumentNullException.ThrowIfNull(x) | Throws with the parameter name | .NET 6 | Guarding public method arguments |
Frequently asked questions
What is the difference between is null and == null in C#?
x is null is a pattern that checks whether the reference itself is null; x == null calls the type's operator == if it defines one. For most types they give the same answer, but a type with an overloaded == can make == null return true for a real object (or false for a null). Prefer is null and is not null. On a non-nullable value type such as int, count is null does not compile (CS0037), while count == null compiles and is always false.
What does the ?? operator do in C#?
a ?? b is the null-coalescing operator: it returns a when a is not null, and b otherwise. It evaluates a once, so Next() ?? "d" calls Next() one time where Next() != null ? Next() : "d" calls it twice. a ??= b assigns b to a only when a is null. Neither treats an empty string as missing; use string.IsNullOrEmpty or string.IsNullOrWhiteSpace for that.
How do I convert an int? to an int?
Decide what null should become. value ?? 0 and value.GetValueOrDefault() give 0 for null, value.GetValueOrDefault(-1) gives your own default, and if (value is int n) checks and unwraps in one step. (int)value and value.Value throw InvalidOperationException: Nullable object must have a value. when it is null, so use them only after checking HasValue. Convert.ToInt32(value) also returns 0 for null.
What causes "Object reference not set to an instance of an object"?
That is the message of NullReferenceException: code called a method, property, field or indexer on a variable that holds null. Common causes are an array whose elements were never assigned, a field never initialized, FirstOrDefault or a dictionary lookup that found nothing, and an as cast that failed. The message never names the variable, so use the line in the stack trace, check each reference on it, and fix the source with ?., ??, a pattern check or an initializer. Enabling nullable reference types makes the compiler warn about most of these.
What does the ! after a variable mean, as in name!.Length?
It is the null-forgiving operator (C# 8). It tells the nullable-reference-types analysis "I know this isn't null" and silences the warning, and it does nothing at run time: string s = null!; followed by s.Length still throws NullReferenceException. Use it only when you know more than the compiler, not to make warnings go away.
How do I check if a string is null or empty in C#?
Use string.IsNullOrEmpty(s), which is true for null and "". string.IsNullOrWhiteSpace(s) is also true for strings made only of spaces, tabs or newlines, so " " and "\t\n" count as blank there and not with IsNullOrEmpty. Both are safe to call on null, unlike s.Length == 0, which throws when s is null.
Can I check for null in a generic method?
Yes: value is null works on an unconstrained T. For a reference type or a nullable value type it does a real null check, and for a non-nullable value type such as int it is simply false. So IsNull<string>(null) is true, IsNull(0) is false and IsNull<int?>(null) is true.