0

我有一个有效的 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 语句,如果满足某些条件,我可以停止并返回一个对象......或者如果不满足条件,则继续执行另一个查询。

也许这很明显,但我真的一无所知。

4

4 回答 4

2

在我看来,这应该对你有用:

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

它工作的关键是给from terminator表达式一个单元素数组来返回空标记 if tryCatchTerminatoris false

于 2019-12-08T23:08:21.023 回答
0

我最终创建了一个直通解析器。它不消耗令牌并返回一个空令牌。

    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);
        };
    }
于 2019-12-09T11:46:19.307 回答
-1

根据您的代码示例,很难判断这是否有效,但我不明白为什么您无法检查 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
于 2019-12-08T22:45:24.730 回答
-1

如果我正确理解了您的问题,那么不,一旦启动查询,就没有(内置)方法可以“停止”查询。如果您想在枚举期间添加相当于取消谓词的内容,这表明枚举是否应该继续,最简单的方法是创建自定义迭代器。这样的实现可能如下所示:

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

唯一的“障碍”是你永远不会想要使用它,除非你可以保证某种形式的排序:例如,所有数字都以有序的顺序出现。如果您没有强制执行此保证,那么您的程序可能会产生不正确的结果。

希望这可以帮助!

于 2019-12-08T23:04:50.397 回答