2008-08-11 80 views
10

我对linq几乎一无所知。Linq to objects - 选择第一个对象

我这样做:

var apps = from app in Process.GetProcesses() 
    where app.ProcessName.Contains("MyAppName") && app.MainWindowHandle != IntPtr.Zero 
    select app; 

这让我匹配标准将所有正在运行的进程。

但我不知道如何得到第一个。我可以在网络上找到的例子似乎意味着我必须这样做

var matchedApp = (from app in Process.GetProcesses() 
    where app.ProcessName.Contains("MyAppName") && app.MainWindowHandle != IntPtr.Zero 
    select app).First(); 

这令我有点丑陋,也抛出一个异常,如果没有匹配的过程。有没有更好的办法?

UPDATE

实际上,我试图找到第一个匹配项,并呼吁它SetForegroundWindow我想出了这个解决方案,这也令我丑陋和可怕

,但比上面好。有任何想法吗?

var unused = from app in Process.GetProcesses() 
    where app.ProcessName.Contains("MyAppName") && app.MainWindowHandle != IntPtr.Zero 
    select SetForegroundWindow(app.MainWindowHandle); // side-effects in linq-query is technically bad I guess 

回答

19

@FryHard FirstOrDefault将工作,但请记住,如果没有找到它,它将返回null。此代码未经测试,但应该接近你想要什么:

var app = Process.GetProcesses().FirstOrDefault(p => p.ProcessName.Contains("MyAppName") && p.MainWindowHandle != IntPtr.Zero); 

if (app == null) 
    return; 

SetForegroundWindow(app.MainWindowHandle); 
+0

如何将它作为查询而不是扩展方法? – 2010-03-25 10:48:54

1

假设在你的第一个例子Apps是一个IEnumerable,你可以利用.Count之间和.FirstOrDefault性能得到你想要传递给SetForegroundWindow的单个项目。

var apps = from app in Process.GetProcesses() 
where app.ProcessName.Contains("MyAppName") && app.MainWindowHandle != IntPtr.Zero 
select app; 

if (apps.Count > 0) 
{ 
    SetForegroundWindow(apps.FirstOrDefault().MainWindowHandle); 
} 
+1

如其他地方所述,这消除了linq(延迟执行)的好处,并且FirstOrDefault对于计数而言是多余的 – 2011-11-18 23:01:50

2

使用Count()像ICR说。 Count()将遍历IEnumerable来找出它有多少个项目。在这种情况下,性能损失可能可以忽略不计,因为进程并不多,但这是一个不好的习惯。当您的查询仅对结果数目感兴趣时,仅使用Count()Count几乎从来都不是一个好主意。

FryHard的答案有几个问题。首先,由于delayed execution,您最终将执行两次LINQ查询,一次获取结果数量,一次获取FirstOrDefault。其次,检查计数后没有任何理由使用FirstOrDefault。既然它可以返回null,你不应该在没有检查null的情况下使用它。无论是做apps.First().MainWindowHandle或:

var app = apps.FirstOrDefault(); 

if (app != null) 
    SetForegroundWindow(app.MainWindowHandle); 

这就是为什么最好的解决方案是马克的,毫无疑问。这是使用LINQ获得你想要的最有效和最稳定的方式。