Here's a simplified version of what I'm trying to do:
var days = new Dictionary<int, string>();
days.Add(1, "Monday");
days.Add(2, "Tuesday");
...
days.Add(7, "Sunday");
var sampleText = "My favorite day of the week is 'xyz'";
var day = days.FirstOrDefault(x => sampleText.Contains(x.Value));
Since 'xyz' is not present in the dictionary, the FirstOrDefault method will not return a valid value. I want to be able to check for this situation but I realize that I can't compare the result to "null" because KeyValuePair is a struc. The following code is invalid:
if (day == null) {
System.Diagnotics.Debug.Write("Couldn't find day of week");
}
We you attempt to compile the code, Visual Studio throws the following error:
Operator '==' cannot be applied to operands of type 'System.Collections.Generic.KeyValuePair<int,string>' and '<null>'
How can I check that FirstOrDefault has returned a valid value?
FirstOrDefault
doesn't return null, it returns default(T)
.
You should check for:
var defaultDay = default(KeyValuePair<int, string>);
bool b = day.Equals(defaultDay);
From MSDN - Enumerable.FirstOrDefault<TSource>
:
default(TSource) if source is empty; otherwise, the first element in source.
Notes:
If your code is generic it is better to use EqualityComparer
In C# 7.1 you will be able to use KeyValuePair
See also: Reference Source - FirstOrDefault
This is the most clear and concise way in my opinion:
var matchedDays = days.Where(x => sampleText.Contains(x.Value));
if (!matchedDays.Any())
{
// Nothing matched
}
else
{
// Get the first match
var day = matchedDays.First();
}
This completely gets around using weird default value stuff for structs.
days
is a Dictionary<int,string>
. So it will be considered as an IEnumerable<KeyValuePair<int,string>>
, then behaving as expected when Any()
and First()
are called. I guess that there are other implementations which can behave differently as IEnumerable<>
. I don't know if I am missing something.
You can do this instead :
var days = new Dictionary<int?, string>(); // replace int by int?
days.Add(1, "Monday");
days.Add(2, "Tuesday");
...
days.Add(7, "Sunday");
var sampleText = "My favorite day of the week is 'xyz'";
var day = days.FirstOrDefault(x => sampleText.Contains(x.Value));
and then :
if (day.Key == null) {
System.Diagnotics.Debug.Write("Couldn't find day of week");
}
Select a list of valid values then check if it contains your day.Value; like this:
var days = new Dictionary<int, string>();
days.Add(1, "Monday");
days.Add(2, "Tuesday");
days.Add(7, "Sunday");
var sampleText = "My favorite day of the week is 'xyz'";
var day = days.FirstOrDefault(x => sampleText.Contains(x.Value));
//check that FirstOrDefault has returned a valid value
if (days.Select(x=>x.Value).Contains(day.Value))
{
//VALID
}
else
{
System.Diagnostics.Debug.Write("Couldn't find day of week");
}
Here's another example using a list of key value pairs:
var days = new List<KeyValuePair<int, string>>();
days.Add(new KeyValuePair<int, string>(1, "Monday"));
days.Add(new KeyValuePair<int, string>(1, "Tuesday"));
days.Add(new KeyValuePair<int, string>(1, "Sunday"));
var sampleText = "My favorite day of the week is 'xyz'";
var day = days.FirstOrDefault(x => sampleText.Contains(x.Value));
//check that FirstOrDefault has returned a valid value
if (days.Select(x => x.Value).Contains(day.Value))
{
//VALID
}
else
{
System.Diagnostics.Debug.Write("Couldn't find day of week");
}
Hope this helps someone!
Success story sharing
typeof
? This code compiles and works.default(KeyValuePair<T1, T2>)
would result in. Ok, it should have been quite obvious, that it would result in an empty KVP. But as "being obvious" is not a good approach to write proper applications (and my current implementation is too complex to clearly/cleanly provoke this case), I tried it with a new project and - indeed - it returned aKeyValuePair
with propertiesKey
andValue
being bothNULL
.... just to safe some other people these 5 minutes of stupidity ;-)default
keyword, it is clearly missing here. Thanks!KeyValuePair
. If you had generic code,day.Equals
is not even null-safe, and I would have usedEqualityComparer<T>.Default.Equals(day, defaultDay)