ChatGPT解决这个技术问题 Extra ChatGPT

How can I make sure that FirstOrDefault<KeyValuePair> has returned a value

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?

You have a bug there, but I assume it's a copy-paste thing: days isn't a list, and you cant use add on KeyValuePair.
ooops... you are correct I was typing from memory and I obviously made a mistake. Thanks for pointing it out.
It was probably: var days = new Dictionary();

T
Tod

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.Default.Equals(day, defaultDay), becuase .Equals may be overridden or day could be a null.

In C# 7.1 you will be able to use KeyValuePair defaultDay = default;, see Target-typed "default" literal.

See also: Reference Source - FirstOrDefault


+1, KeyValuePair is a value type (struct), not a reference type (class) or a nullable value type, so it cannot be null.
@paper1337 - Thanks, but where am I missing typeof? This code compiles and works.
I came here because it wasn't clear to me, what 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 a KeyValuePair with properties Keyand Value being both NULL .... just to safe some other people these 5 minutes of stupidity ;-)
@Nicolas - No stupidity here. It's always a good idea to check for yourself and make sure you understand your code. I've added a link to the default keyword, it is clearly missing here. Thanks!
@JeffBridgman - That's really a good point! Specifically here it is not possible, because we are working with KeyValuePair. If you had generic code, day.Equals is not even null-safe, and I would have used EqualityComparer<T>.Default.Equals(day, defaultDay)
p
peaceoutside

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.


Problem with this, is that there is potential (depending on implementation) that the days enumerable will be enumerated twice, or even worse, return different values between the Any() and the First() calls
@RayBooysen A call of ToArray or ToList solves the problem and you can use Count/Length and a Indexer.
Note that @Ray's answer does not apply here, because 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.
J
Jocelyn Marcotte

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");
}

M
MeatBomb

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!


The question is about KeyValuePair not about dictionary
@Serge; thanks, you're right. I added an example using a list of key value pairs

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now