2008-08-11 79 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獲得你想要的最有效和最穩定的方式。