簡體   English   中英

有沒有辦法在 c# 中使用 if-else 語句來簡化 LINQ 語句

[英]Is there way to simplify a LINQ statement using if-else statement in c#

我有一個有效的 LINQ 表達式,但我想讓它更簡單、更清晰。

var tryCatchTerminator = true;

return tryCatchTerminator
            ? from varKeyword in MatchToken(SyntaxKind.VarKeyword)
            from declarations in ParseVarDeclarationClause.AtLeastOnceDelimitedBy(MatchToken(SyntaxKind.Comma))
            from terminator in MatchToken(SyntaxKind.SemiColon).OptionalOrDefault()
            select (StatementSyntax) new VarDeclarationStatement(varKeyword, declarations, terminator)
            : from varKeyword in MatchToken(SyntaxKind.VarKeyword)
            from declarations in ParseVarDeclarationClause.AtLeastOnceDelimitedBy(MatchToken(SyntaxKind.Comma))
            select (StatementSyntax) new VarDeclarationStatement(varKeyword, declarations, Token<SyntaxKind>.Empty);

我在互聯網上尋找某種方式在 LINQ 表達式中包含 if 語句,如果滿足某些條件,我可以停止並返回一個對象……或者如果不滿足條件,則繼續執行另一個查詢。

也許這很明顯,但我真的一無所知。

在我看來,這應該適合你:

return
    from varKeyword in MatchToken(SyntaxKind.VarKeyword)
    from declarations in ParseVarDeclarationClause.AtLeastOnceDelimitedBy(MatchToken(SyntaxKind.Comma))
    from terminator in tryCatchTerminator ? MatchToken(SyntaxKind.SemiColon).OptionalOrDefault() : new[] { Token<SyntaxKind>.Empty } 
    select (StatementSyntax)new VarDeclarationStatement(varKeyword, declarations, terminator);

如果tryCatchTerminatorfalse ,它工作的關鍵就是給from terminator表達式一個單元素數組以返回空標記。

我最終創建了一個直通解析器..它不消耗令牌並返回一個空令牌。

    private static TokenListParser<SyntaxKind, StatementSyntax> ParseExpressionStatement(
            bool lookForTerminator)
    {
        return from expression in ParsePrefixExpression.Or(ParseCallExpression())
                from terminator in lookForTerminator
                    ? MatchToken(SyntaxKind.SemiColon).OptionalOrDefault()
                    : PassThrough<SynaxKind>()
                select (StatementSyntax) new ExpressionStatementSyntax(expression, terminator);
    }

    private static TokenListParser<T, Token<T>> PassThrough<T>(Token<T> empty)
    {
        return input =>
        {
            var output = input.ConsumeToken();
            return TokenListParserResult.Value(Token<T>.Empty, output.Location, output.Location);
        };
    }

很難根據您的代碼示例判斷這是否有效,但我不明白為什么您無法檢查 LINQ 查詢中的條件:

return from varKeyword in MatchToken(SyntaxKind.VarKeyword)
          from declarations in ParseVarDeclarationClause.AtLeastOnceDelimitedBy(MatchToken(SyntaxKind.Comma))
          from terminator in MatchToken(SyntaxKind.SemiColon).DefaultIfEmpty()
          select (StatementSyntax)new VarDeclarationStatement(varKeyword, declarations, tryCatchTerminator ? terminator : Token<SyntaxKind>.Empty); // check here and pass correct value to VarDeclarationStatement

如果我正確理解您的問題,那么不,一旦查詢開始,就沒有(內置)方法可以“停止”查詢。 如果您想在枚舉期間添加等於取消謂詞的內容,這表明枚舉是否應該繼續,最簡單的方法是創建自定義迭代器。 這樣的實現可能如下所示:

public sealed class BreakingEnumerable<T> : IEnumerable<T>
{
    private readonly IEnumerable<T> _query;
    private readonly Predicate<T> _continuePredicate;

    public BreakingEnumerable(IEnumerable<T> query, Predicate<T> predicate)
    {
        _query = query ?? throw new ArgumentNullException(nameof(query));
        _continuePredicate = predicate ?? throw new ArgumentNullException(nameof(predicate));
    }

    public IEnumerator<T> GetEnumerator()
    {
        foreach (var item in _query)
        {
            if (_continuePredicate(item))
            {
                yield return item;
            }
            else
            {
                yield break;
            }
        }
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

當然,您希望將這部分作為查詢的一部分,因此您可能需要一個擴展方法類來將查詢轉換這個自定義可枚舉:

public static class BreakingEnumerableExtensions {
    public static BreakingEnumerable<T> WithTerminationClause<T>(
        this IEnumerable<T> query,
        Predicate<T> breakCondition)
    {
        return new BreakingEnumerable<T>(query, breakCondition);
    }
}

這是實際用法:

static void Main(string[] args)
{
    var enumerable = Enumerable.Range(1, 100);

    var array = enumerable.WithTerminationClause(i => i > 100).ToArray();
    Console.WriteLine($"Enumerable with termination clause array length: {array.Length}");

    array = enumerable.Where(i => i < 20).WithTerminationClause(i => i % 2 == 0)
        .ToArray();

    Console.WriteLine($"Enumerable with termination clause length: {array.Length}");
}

結果如下:

Enumerable with termination clause array length: 0
Enumerable with termination clause length: 9

這可以鏈接以產生一些小的優化:

// Outputs: `Query results: [100, 200, 300]`
var enumerable = Enumerable.Range(1, 100);

var sub = enumerable.WithTerminationClause(i => i <= 3)
    .Select(i => i * 100);
Console.WriteLine("Query results: [{0}]", string.Join(", ", sub));

唯一的“障礙”是您永遠不會想要使用它,除非您可以保證某種形式的排序:例如,所有數字都以有序的順序出現。 如果您沒有強制執行此保證,則您的程序可能會產生不正確的結果。

希望這可以幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM