Joe*_*ley 4 linq tryparse out-parameters trygetvalue c#-4.0
这段代码有效,但效率低下,因为它重复查找ignored字典。如何TryGetValue()在 LINQ 语句中使用字典方法使其更高效?
IDictionary<int, DateTime> records = ...
IDictionary<int, ISet<DateTime>> ignored = ...
var result = from r in records
where !ignored.ContainsKey(r.Key) ||
!ignored[r.Key].Contains(r.Value)
select r;
Run Code Online (Sandbox Code Playgroud)
问题是我不确定如何在 LINQ 语句中声明一个用于 out 参数的变量。
(我的回答涉及使用TrySomething( TInput input, out TOutput value )方法的一般情况(比如IDictionary.TryGetValue( TKey, out TValue )andInt32.TryParse( String, out Int32 )所以它没有直接用 OP 自己的示例代码回答 OP 的问题。我在这里发布这个答案是因为这个 QA 目前是“linq trygetvalue "截至 2019 年 3 月)。
使用扩展方法语法时,至少有这两种方法。
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();
Run Code Online (Sandbox Code Playgroud)
这实际上可以通过利用另一个巧妙的技巧来简化,其中value变量在整个.Selectlambda的范围内,因此三元表达式变得不必要,如下所示:
// 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();
Run Code Online (Sandbox Code Playgroud)
使用 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();
Run Code Online (Sandbox Code Playgroud)
使用 .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();
Run Code Online (Sandbox Code Playgroud)
我编写了自己的扩展方法:将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;
}
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
// 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();
Run Code Online (Sandbox Code Playgroud)
如果您仍想使用 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;
}
}
Run Code Online (Sandbox Code Playgroud)
用法:
// 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();
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为 C# 7.0 允许在out Type name表达式中声明的变量用于其他元组值。
您需要out在查询之前声明变量:
ISet<DateTime> s = null;
var result = from r in records
where !ignored.TryGetValue(r.Key, out s)
|| !s.Contains(r.Value)
select r;
Run Code Online (Sandbox Code Playgroud)
不过,如果稍后才评估查询,请小心副作用......
| 归档时间: |
|
| 查看次数: |
6855 次 |
| 最近记录: |