相关文章推荐
犯傻的绿茶  ·  C# 之 ...·  1 周前    · 
耍酷的书签  ·  maven导入Gson_class_bric ...·  1 年前    · 
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I have the following LINQ query that fires an exception when the FirstOrDefault() returns null. Ideally I would like to avoid the null check. Is there a way to do this? I wish to return 0 if there are no CPOffsets that satisfy the FirstOrDefault() call.

double offset = OrderedOffsets.FirstOrDefault(o => o.OffsetDateTime > cpTime).CPOffset;

The only way I can see to achieve this is the following:

CPOffset cpOffset = OrderedOffsets.FirstOrDefault(o => o.OffsetDateTime > cpTime);
double offset = cpOffset != null ? cpOffset.CPOffset : 0;

Is there another more succinct way? Using Select() after the FirstOrDefault() doesn't compile but I thought might be appropriate here?

This is really about as succinct as you are going to get... most of the time "good enough" is good enough :-) – theMayer Mar 20, 2013 at 23:47 I agree. If you want it more succinct you'll probably have to roll your own method or extension method. (which isn't necessarily a bad thing) EDIT: Nothing wrong with double offset = DetermineOffset(OrderedOffsets, cpTime); or double offset = OrderedOffsets.DetermineOffset(cpTime) or double offset = OrderedOffsets.DetermineOffset(o => o.OffsetDateTime > cpTime); if you want a bit more control over the predicate. – Chris Sinclair Mar 20, 2013 at 23:48 @Servy , suppose First would be enough. How much better would it be than using FirstOrDefault? 9 chars? – I4V Mar 21, 2013 at 0:05 Slow, i wrote a own solution for this which is not iterating through the complete collection ( thats what he does with where ). – Felix K. Oct 27, 2013 at 19:08 @felix-k - don't quite follow you there; I don't think this solution will iterate through the complete collection. The Where is an iterator and will only be called as often as needed. The FirstOrDefault will stop after the first item it finds. – jdpilgrim Feb 19, 2015 at 10:48 @jdpilgrim You're right, at this time i didn't know this. But still its somehow nicer to have it in one single method call because its easier to read. – Felix K. Feb 19, 2015 at 14:22

DefaultIfEmpty can be used to ensure that the collection always has at least one element.

double offset = OrderedOffsets.Where(o => o.OffsetDateTime > cpTime)
    .Select(o => o.CPOffset)
    .DefaultIfEmpty()
    .First();
                Is this different or better than just calling FirstOrDefault() after the Select() like in the accepted answer?
– JohnB
                May 18, 2022 at 14:48
                @JohnB The main advantage is being able to provide the default value rather than it needing to be the default value of that type.
– Servy
                May 18, 2022 at 16:35

I think a good pattern could be :

double offset = (OrderedOffsets.FirstOrDefault(o => o.OffsetDateTime > cpTime) ?? someDefaultObject).CPOffset;

with someDefaultObject an object holding default values... With this pattern, you can change easily you default values through your code !

If OrderedOffsets can be a struct you could also just put your default value there ! :)

OK, this would work, but, why do you think this would be better than NSGaga's answer. It doesn't require a temp obejct someDefaultObject and more readable(of course subjective) – L.B Mar 21, 2013 at 0:45 yeah but i don't really like that we keep all the values > cpTime after the Where i prefer a method that return after it find the first element, what if the list is megahuge, do we really want to project all the CPOffset passing in a new form ? I think it's not worth it to save a line… I'd rather go for the two line initially in the question… – Romain Mar 21, 2013 at 0:55 I think you should read more on Linq and lazy evaluation. NSGaga's answer will return as soon as it finds the first match. It would iterate all the list if it doesn't find a match which is also true for your answer. – L.B Mar 21, 2013 at 1:29 PS: Where and Select doesn't keep all the list in memory, they just read the items one by one. This is what IEnumerable<T> exists for. – L.B Mar 21, 2013 at 1:35 @Romain The Where will fetch OffsetDateTime the exact same number of times in your query as both mine and NSGaga's, it will get it for every element until it finds a match, or all of them if there is no match. The Select that fetches CPOffset will be applied to at most one item in both mine and Gaga's answers, due to the lazy evaluation and potentially incomplete iteration of the Select. – Servy Mar 21, 2013 at 14:16

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.