2008-08-11 3 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

Предполагая, что в первом примере приложения является 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 почти никогда не является хорошей идеей.

Есть несколько проблем с ответом Фрай Харда. Во-первых, из-за delayed execution вы в конечном итоге выполните запрос LINQ дважды, один раз, чтобы получить количество результатов, и один раз, чтобы получить FirstOrDefault. Во-вторых, нет никакой причины использовать FirstOrDefault после проверки счета. Поскольку он может возвращать null, вы никогда не должны использовать его, не проверяя значение null. Либо сделать apps.First().MainWindowHandle или:

var app = apps.FirstOrDefault(); 

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

Поэтому лучшим решением является Марк, без вопросов. Это самый эффективный и стабильный способ использования LINQ для получения того, что вы хотите.

Смежные вопросы