Pergunta

Is there syntactic sugar or a method to "short-circuit" a LINQ statement within the same line when written in fluent syntax? For example if null is returned by a FirstOrDefault call, is it possible to return null otherwise continue with the rest of the method chain?

List<string> testList = new List<string>() { "some", "strings" };
var reversed = testList.FirstOrDefault(x => x == "hello").Reverse();

The FirstOrDefault call will return null so the statement will throw an ArgumentNullException on the Reverse call. Is there a way of stopping before the Reverse call since the default value was returned at that point?

(I know that the query can be broken into another line and default(T) can be checked before Reverse or, for simple cases, the conditional operator (?:) can be used but I'm curious if I'm missing a particular feature for longer/more complex chains)

Edit - To clarify this is just an example to show the idea, it's not part of any actual code. I'd like to avoid exceptions being thrown as it would be more performant to just split the line and do a check.

Foi útil?

Solução

In cases where you want to resolve the set to a single item and manipulate that item, but still gracefully handle situations where that item may not be found in the set, you can can delay the FirstOrDefault until the very end, like this:

var reversed = testList
    .Where(x => x == "hello")
    .Select(x => x.Reverse())
    .FirstOrDefault();

Or equivalently

var reversed = testList
    .Where(x => x == "hello")
    .Select(Enumerable.Reverse)
    .FirstOrDefault();

This will return null if no items are in the list that satisfy the condition specified in the Where method. The performance difference here will be at most negligible. It won't require looping through the testList any more than the original code, since once the first element is found, the result is immediately returned.

Outras dicas

Yes, just use First instead of FirstOrDefault; it will throw an exception earlier.

It looks like you're after a C# version of the maybe monad.

public static class MaybeMonadExtensions
{
    public static TResult GetIfNotNull<TInput, TResult>(this TInput o, Func<TInput, TResult> evaluator)
        where TResult : class
        where TInput : class
    {
        return o == null ? null : evaluator(o);
    }
}

Using this, you can write

var reversed = testList.FirstOrDefault(x => x == "hello").GetIfNotNull(s => s.Reverse());

and that will output null if your list does not contain the word "hello".

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top