有没有办法在 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 一个对象...或者继续执行另一个查询如果不满足条件。
也许这是显而易见的,但我真的一无所知。
根据您的代码示例很难判断这是否可行,但我不明白您为什么不能检查 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
如果我正确理解您的问题,那么不,一旦启动查询,就没有(内置)方法 "stop" 查询。如果您想在枚举期间添加相当于取消谓词的内容,这表明枚举是否应继续,最简单的方法是创建自定义迭代器。这样的实现可能如下所示:
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();
}
}
当然,您希望将这部分作为查询的一部分,因此您可能需要扩展方法 class 将查询 转换为 自定义可枚举:
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));
唯一的 "hitch" 是你永远不想使用它,除非你能保证某种形式的排序:例如,所有数字都按顺序出现。如果您不强制执行此保证,那么您的程序可能会产生不正确的结果。
希望对您有所帮助!
在我看来这应该适合你:
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);
它工作的关键是如果 tryCatchTerminator
是 false
.[=14=,就给 from terminator
表达式一个单元素数组到 return 空标记]
我最终创建了一个直通解析器..它不消耗令牌并且returns一个空令牌。
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 表达式,但我想让它更简单、更清晰。
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 一个对象...或者继续执行另一个查询如果不满足条件。
也许这是显而易见的,但我真的一无所知。
根据您的代码示例很难判断这是否可行,但我不明白您为什么不能检查 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
如果我正确理解您的问题,那么不,一旦启动查询,就没有(内置)方法 "stop" 查询。如果您想在枚举期间添加相当于取消谓词的内容,这表明枚举是否应继续,最简单的方法是创建自定义迭代器。这样的实现可能如下所示:
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();
}
}
当然,您希望将这部分作为查询的一部分,因此您可能需要扩展方法 class 将查询 转换为 自定义可枚举:
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));
唯一的 "hitch" 是你永远不想使用它,除非你能保证某种形式的排序:例如,所有数字都按顺序出现。如果您不强制执行此保证,那么您的程序可能会产生不正确的结果。
希望对您有所帮助!
在我看来这应该适合你:
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);
它工作的关键是如果 tryCatchTerminator
是 false
.[=14=,就给 from terminator
表达式一个单元素数组到 return 空标记]
我最终创建了一个直通解析器..它不消耗令牌并且returns一个空令牌。
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);
};
}