我有这个功能:
public IEnumerable<string> EnumPrograms() {
return dev.AudioSessionManager2.Sessions.AsEnumerable()
.Where(s => s.GetProcessID != 0)
.Select(s => {
try {
return Process.GetProcessById((int)s.GetProcessID).ProcessName;
}
catch (ArgumentException) {
return null;
}
});
}
try..catch是必要的,因为可能存在具有不再存在的PID的会话。我想跳过它们。有没有办法从Select
回调做到这一点,还是我需要添加跳过Where
值的新null
条件?
不,Select
总是为每个输入元素产生一个输出元素。除此之外别无选择。您可以轻松编写自己的FilteredSelect
扩展方法 - 但使用Where
子句更简单。
或者,使用Process.GetProcesses()
获取所有进程的快照,然后将其加入会话集合(或使用类似的东西)。这样可以避免丑陋的捕获:
var sessionProcessIds = new HashSet<int>(dev.AudioSessionManager2.Sessions
.AsEnumerable()
.Select(x => x.GetProcessId)
.Where(pid => pid != 0));
var processes = Process.GetProcesses();
var sessionProcessNames = processes.Where(p => sessionProcessIds.Contains(p.Id))
.Select(p => p.ProcessName);
要么:
var names = from session in dev.AudioSessionManager2.Sessions.AsEnumerable()
let pid = session.GetProcessId
where pid != 0
join process in Process.GetProcesses() on pid equals process.Id
select process.ProcessName;
Linq的Select
相当于Map
,而Aggregate
相当于Reduce
。 Map / Select是1:1输入到输出。如果没有1:1的关系,你想使用Reduce
/ Aggregate
。
public IEnumerable<string> EnumPrograms() {
return dev.AudioSessionManager2.Sessions.AsEnumerable()
.Where(s => s.GetProcessID != 0)
.Aggregate(new List<string>(), (acc, s) => {
try {
var proc = Process.GetProcessById((int)s.GetProcessID).ProcessName;
acc.Add(proc);
} catch (ArgumentException) { }
return acc;
});
}
Select
本身不能这样做,你可以为@Jon Skeet提到的那样创建一个自定义扩展方法。
public static IEnumerable<TResult> FilteredSelect<TSource, TResult>(
this IEnumerable<TSource> source
, Func<TSource, bool> predicate
, Func<TSource, TResult> selector)
{
foreach (var item in source)
{
if (predicate(item))
{
yield return selector(item);
}
}
}
并用作
elements.FilteredSelect(/* where condition */, /* select values */);
在John Skeet的帖子的基础上,这种扩展方法为我节省了无数的代码。这个名字非常适合SelectWhere。下面的代码清单是您可以使用的扩展方法。
public static IEnumerable<TResult> SelectWhere<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector, Func<TSource, bool> predicate)
{
foreach (TSource item in source)
if (predicate(item))
yield return selector(item);
}
用法:
entity.SelectWhere(e => /* returned element */, e => /* bool condition */);