C# Check Variable == Null

I have the below code.
var idx = dictNames2Indexes.FirstOrDefault(x => x.Key.Contains(value)).Value;

if (idx != null)
   ......

Open in new window

I am receiving "The result of the expression is always 'true' since a value of type 'int' is never equal to 'null' of type 'int?'"

Shouldn't above check for nulls?
LVL 2
CipherISAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Shaun VermaakTechnical SpecialistCommented:
Check for null on
dictNames2Indexes.FirstOrDefault(x => x.Key.Contains(value))

Open in new window

not on
dictNames2Indexes.FirstOrDefault(x => x.Key.Contains(value)).Value

Open in new window

aranaCommented:
int is a value type, value types cant be nulled.

you will have to create/declare your idx as nullable
CipherISAuthor Commented:
@aarana - I'm using Var.  Also, I tried delcaring int? idx but I still get the same issue.
Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

CipherISAuthor Commented:
@Shaun - that doesn't work

Error      6      Operator '!=' cannot be applied to operands of type 'System.Collections.Generic.KeyValuePair<string,int>' and '<null>'
Fernando SotoRetiredCommented:
Hi CipherIS;

It looks like dictNames2Indexes is a Dictionary<string, int>, if so your statement
var idx = dictNames2Indexes.FirstOrDefault(x => x.Key.Contains(value)).Value;

Open in new window

Should return 0 if it could not find the Key and the assigned value if it does find the Key. If that is not happening please post the code where you define dictNames2Indexes in your code.

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
gr8gonzoConsultantCommented:
The answer is scatted among the previous comments, so let me try to take a stab at explaining it.

So first off, .NET is correct when it is saying that idx will never be null. The dictName2Indexes is a Dictionary<string,int> which means that all the VALUES of this dictionary are "int" types, and "int" can never be null.

In .NET, there are several value types that can never be null, like int and DateTime and bool.

For example, try running this line of code in .NET:
bool testBoolean = null;

Open in new window


It'll tell you it can't do that because "bool" is a non-nullable type.

So for any of these types of values (int, DateTime, bool), if you don't specify their value, then their default value is not null, but something specific to the type of data they have.
bool testBoolean; // Default value is false
int testInteger; // Default value is 0
DateTime testDateTime; // Default value is DateTime.MinValue

Open in new window


It is very easy to tell .NET to allow them to be null, though. You simply add a ? to the end of the data type:
bool? testBoolean; // Default value is null
int? testInteger; // Default value is null
DateTime? testDateTime; // Default value is null

Open in new window


So by declaring testInteger as an int? type, it can now be null or it can be a number.

So coming back to your dictionary, if your dictionary is a Dictionary<string, int> type, then the FirstOrDefault() call like this:
dictNames2Indexes.FirstOrDefault(...criteria here...)

Open in new window


...will return the first matching KeyValuePair entry for a successful match. If it's unsuccessful, then you get back a KeyValuePair object that contains the default values for string (your dictionary's key type) and int (your dictionary's value type). So the unsuccessful search would return a KeyValuePair of { null, 0 } (string is a nullable value type so you don't need a ? at the end of it).

Then when you add .Value to the end of that, you're pulling the value, which for the unsuccessful search would be 0.

So when you have this line of code after your search:
if (idx != null)

Open in new window

...then .NET is complaining and saying, "I'm either going to have a successful search and return an integer, or I'm going to have an unsuccessful search and return 0, which is an integer. So no matter what, I'm returning an int, which is not nullable."

As to what you can do here, if 0 is a valid number in your scenario (I'm guessing this is related to that Excel spreadsheet thing, so 0 could be a valid column index), then you'd just change your dictionary definition to have that ? after the int:

Dictionary<string,int?> dictNames2Indexes = new ...blah blah...

Now when you have an unsuccessful search in FirstOrDefault, your default KeyValuePair will be {null, null}, so your null check on idx will work as expected.
Edgard YamashitaSystems AnalystCommented:
If your variable dictNames2Indexes is a dictionary, then you should check for the key before, and if it exists get the value (without the need to check for null if the key exists).

Eg:
            Dictionary<string, int> dictNames2Indexes = new Dictionary<string, int>()
            {
                { "TEST", 1 }
            };

            if(dictNames2Indexes.ContainsKey("TEST"))
            {
                int idx = dictNames2Indexes["TEST"];
            }

Open in new window

it_saigeDeveloperCommented:
*NO POINTS*

Others have explained why you are getting your error.  However, since keys in a Dictionary must be unique, you should really be using the TryGetValue method.  Example -
using System;
using System.Collections.Generic;
using System.Linq;

namespace EE_Q29126855
{
	class Program
	{
		static readonly Dictionary<string, int> numbers = (from i in Enumerable.Range(0, 20)
														   select new { Key = $"Key{i}", Value = i }).ToDictionary(pair => pair.Key, pair => pair.Value, StringComparer.OrdinalIgnoreCase);
		static void Main(string[] args)
		{
			int value = default(int);
			Console.WriteLine($"Default integer is 0: {value == 0}");
			foreach (var i in Enumerable.Range(15, 6))
			{
				if (numbers.TryGetValue($"Key{i}", out value))
				{
					Console.WriteLine($"Value of Key{i} is {value}");
				}
				else
				{
					Console.WriteLine($"Key{i} not found in dictionary; value is 0: {value == 0}");
				}
			}
			Console.ReadLine();
		}
	}
}

Open in new window

Produces the following output -Capture.PNG-saige-
Kelvin McDanielSr. DeveloperCommented:
These are all very informative answers, and each is good for learning. In the spirit of your original question, however, I think you'll want to use the following check:

if (dictNames2Indexes.Any(x => x.Key.Contains(value))
{
	var idx = dictNames2Indexes.FirstOrDefault(x => x.Key.Contains(value)).Value;
	...
}

Open in new window


Note that I assume you don't need idx outside of the if block.

The important thing to remember here is that an initialized Dictionary<T, TV> won't ever have completely null entries. At worst (and as has already been said), it will return an empty KeyValuePair<T, TV> with the default values for T (the key) and TV (the value). In your case the default key value is "" and the default Value for that key is 0.
Shaun VermaakTechnical SpecialistCommented:
@Shaun - that doesn't work
Probably
dictNames2Indexes.Where(x => x.Key.Contains(value)).FirstOrDefault()

Open in new window

Alfredo Luis Torres SerranoASP .Net DeveloperCommented:
For an int with ? at the end (Nullable) the default value is null

intNullableDefault.png
I would recommend to test the dictNames2Indexes  content
CipherISAuthor Commented:
Thanks for the all the info.

@Fernando - that is the solution I came up with also.
Fernando SotoRetiredCommented:
Not a problem CipherIS, glad to help.
gr8gonzoConsultantCommented:
Just be careful, since "0" might be a legitimate value.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.