我有这个功能:
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
条件?
答案 0 :(得分:20)
不,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;
答案 1 :(得分:3)
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;
});
}
答案 2 :(得分:1)
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 */);
答案 3 :(得分:0)
基于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 */);
答案 4 :(得分:0)
这是使用LINQ的扩展方法的简单版本:
isTranslucent
答案 5 :(得分:0)
正如其他人所说,Select
总是为每个输入元素产生一个输出元素,但如果您的情况是根据类型进行过滤,那么您可以使用 Enumerable.OfType<TResult>(IEnumerable)
- https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.oftype?view=net-5.0
例如这个:
var agents = data.Where(d => d is Agent).Select(d => d as Agent);
相当于:
var agents = data.OfType<Agent>();