(我的回答涉及使用TrySomething( TInput input, out TOutput value )
方法的一般情况(例如IDictionary.TryGetValue( TKey, out TValue )
,Int32.TryParse( String, out Int32 )
它并没有直接用 OP 自己的示例代码回答 OP 的问题。我在这里发布这个答案是因为这个 QA 目前是“linq trygetvalue”的最佳 Google 结果“截至 2019 年 3 月)。
使用扩展方法语法时,至少有这两种方法。
1. 使用 C# 值元组System.Tuple
、 或匿名类型:
在调用中首先调用该TrySomething
方法Select
,并将结果存储在 C# 7.0 中的值元组中(或旧版本 C# 中的匿名类型,请注意,值元组应优先考虑,因为它们的开销较低):
使用 C# 7.0 值元组(推荐):
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };
List<Int32> integersInInput = input
.Select( text => Int32.TryParse( text, out Int32 value ) ? ( ok: true, value ) : ( ok: false, default(Int32) ) )
.Where( t => t.ok )
.Select( t => t.value )
.ToList();
这实际上可以通过利用另一个巧妙的技巧来简化,其中value
变量在整个.Select
lambda 的范围内,因此三元表达式变得不必要,如下所示:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };
List<Int32> integersInInput = input
.Select( text => ( ok: Int32.TryParse( text, out Int32 value ), value ) ) // much simpler!
.Where( t => t.ok )
.Select( t => t.value )
.ToList();
使用 C# 3.0 匿名类型:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };
List<Int32> integersInInput = input
.Select( text => Int32.TryParse( text, out Int32 value ) ? new { ok = true, value } : new { ok = false, default(Int32) } )
.Where( t => t.ok )
.Select( t => t.value )
.ToList();
使用 .NET Framework 4.0 Tuple<T1,T2>
:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };
List<Int32> integersInInput = input
.Select( text => Int32.TryParse( text, out Int32 value ) ? Tuple.Create( true, value ) : Tuple.Create( false, default(Int32) ) )
.Where( t => t.Item1 )
.Select( t => t.Item2 )
.ToList();
2.使用扩展方法
我编写了自己的扩展方法:SelectWhere
将其简化为一次调用。它应该在运行时更快,尽管它不重要。
delegate
它通过为具有第二个out
参数的方法声明自己的类型来工作。Linq 默认不支持这些,因为System.Func
不接受out
参数。但是,由于委托在 C# 中的工作方式,您可以TryFunc
与任何与其匹配的方法一起使用,包括Int32.TryParse
、Double.TryParse
、Dictionary.TryGetValue
等等......
要支持Try...
具有更多参数的其他方法,只需定义一个新的委托类型并为调用者提供一种指定更多值的方法。
public delegate Boolean TryFunc<T,TOut>( T input, out TOut value );
public static IEnumerable<TOut> SelectWhere<T,TOut>( this IEnumerable<T> source, TryFunc<T,TOut> tryFunc )
{
foreach( T item in source )
{
if( tryFunc( item, out TOut value ) )
{
yield return value;
}
}
}
用法:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };
List<Int32> integersInInput = input
.SelectWhere( Int32.TryParse ) // The parse method is passed by-name instead of in a lambda
.ToList();
如果您仍想使用 lambda,另一种定义使用值元组作为返回类型(需要 C# 7.0 或更高版本):
public static IEnumerable<TOut> SelectWhere<T,TOut>( this IEnumerable<T> source, Func<T,(Boolean,TOut)> func )
{
foreach( T item in source )
{
(Boolean ok, TOut output) = func( item );
if( ok ) yield return output;
}
}
用法:
// Task: Find and parse only the integers in this input:
IEnumerable<String> input = new[] { "a", "123", "b", "456", ... };
List<Int32> integersInInput = input
.SelectWhere( text => ( Int32.TryParse( text, out Int32 value ), value ) )
.ToList();
这是因为 C# 7.0 允许在out Type name
表达式中声明的变量用于其他元组值。