C# IEnumerable.Select()是否可以跳过项目?
我有这个功能:C# IEnumerable.Select()是否可以跳过项目?,c#,ienumerable,C#,Ienumerable,我有这个功能: public IEnumerable<string> EnumPrograms() { return dev.AudioSessionManager2.Sessions.AsEnumerable() .Where(s => s.GetProcessID != 0) .Select(s => { try { return Process.GetProcessByI
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;
}
});
}
public IEnumerable枚举程序(){
返回dev.AudioSessionManager2.Sessions.AsEnumerable()
.Where(s=>s.GetProcessID!=0)
。选择(s=>{
试一试{
返回Process.GetProcessById((int)s.GetProcessID).ProcessName;
}
捕获(异常){
返回null;
}
});
}
try..catch是必需的,因为可能存在PID不再存在的会话。我想跳过它们。是否有办法从
Select
回调中执行此操作,或者是否需要添加一个新的Where
条件以跳过null
值?否,Select
始终为每个输入元素生成一个输出元素。除此之外别无选择。您可以很容易地编写自己的FilteredSelect
扩展方法,但使用Where
子句更简单
或者,使用Process.getprocesss()
获取所有进程的快照,然后将其加入会话集合(或使用类似的方法)。这将避免丑陋的陷阱:
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);
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);
}
}
}
Linq中的
Select
相当于Map
,而Aggregate
相当于Reduce
。映射/选择是1:1输入到输出。如果不存在1:1关系,则要使用减少
/聚合
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;
});
}
public IEnumerable枚举程序(){
返回dev.AudioSessionManager2.Sessions.AsEnumerable()
.Where(s=>s.GetProcessID!=0)
.Aggregate(新列表(),(acc,s)=>{
试一试{
var proc=Process.GetProcessById((int)s.GetProcessID).ProcessName;
acc.Add(程序);
}捕获(参数异常){}
返回acc;
});
}
基于John Skeet的帖子,这种扩展方法为我节省了无数行代码。名称非常适合选择where。下面列出的代码是您可以使用的扩展方法
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);
}
下面是使用LINQ的扩展方法的更简单版本:
public static IEnumerable<TResult> FilteredSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
{
return source
.Where(item => predicate(item))
.Select(item => selector(item));
}
public static IEnumerable FilteredSelect(此IEnumerable源、Func谓词、Func选择器)
{
返回源
.其中(项=>谓词(项))
.选择(项目=>选择器(项目));
}
正如其他人所说的Select
总是为每个输入元素生成一个输出元素,但是如果您的案例是基于类型进行过滤,那么您可以使用可枚举的类型(IEnumerable)
-
例如:
var-agents=data。其中(d=>d是代理)。选择(d=>d作为代理);
相当于:
var-agents=data.OfType();
第二个建议听起来很有趣。但是带有音频会话的进程只是正在运行的进程的一小部分,所以我想它的效率会稍低一些(在这种情况下这并不重要)?@ThiefMaster:我不知道Process.GetProcesses()
需要多长时间,但至少你只能调用它一次,而不是每次会话调用一次。@ThiefMaster我很确定getProcesss
和GetProcessByID
都在幕后调用enumProcesss
。
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 => e.FirstName, e => e.Age>25);
public static IEnumerable<TResult> FilteredSelect<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, Func<TSource, TResult> selector)
{
return source
.Where(item => predicate(item))
.Select(item => selector(item));
}