CipherIS
asked on
C# Check Variable == Null
I have the below code.
Shouldn't above check for nulls?
var idx = dictNames2Indexes.FirstOrDefault(x => x.Key.Contains(value)).Value;
if (idx != null)
......
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?
int is a value type, value types cant be nulled.
you will have to create/declare your idx as nullable
you will have to create/declare your idx as nullable
ASKER
@aarana - I'm using Var. Also, I tried delcaring int? idx but I still get the same issue.
ASKER
@Shaun - that doesn't work
Error 6 Operator '!=' cannot be applied to operands of type 'System.Collections.Generi c.KeyValue Pair<strin g,int>' and '<null>'
Error 6 Operator '!=' cannot be applied to operands of type 'System.Collections.Generi
ASKER CERTIFIED SOLUTION
membership
Create a free account to see this answer
Signing up is free and takes 30 seconds. No credit card required.
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:
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.
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:
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:
...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:
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.
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;
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
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
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...)
...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)
...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.
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:
Eg:
Dictionary<string, int> dictNames2Indexes = new Dictionary<string, int>()
{
{ "TEST", 1 }
};
if(dictNames2Indexes.ContainsKey("TEST"))
{
int idx = dictNames2Indexes["TEST"];
}
*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 -
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();
}
}
}
Produces the following output --saige-
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:
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.
if (dictNames2Indexes.Any(x => x.Key.Contains(value))
{
var idx = dictNames2Indexes.FirstOrDefault(x => x.Key.Contains(value)).Value;
...
}
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 - that doesn't workProbably
dictNames2Indexes.Where(x => x.Key.Contains(value)).FirstOrDefault()
ASKER
Thanks for the all the info.
@Fernando - that is the solution I came up with also.
@Fernando - that is the solution I came up with also.
Not a problem CipherIS, glad to help.
Just be careful, since "0" might be a legitimate value.
Open in new window
not onOpen in new window