Linq to objects - выберите первый объект

Я почти ничего не знаю о linq.

Я делаю это:

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();

что кажется мне несколько уродливым, а также выдает исключение, если нет подходящих процессов. Есть ли способ лучше?

ОБНОВИТЬ

На самом деле я пытаюсь найти первый подходящий элемент и вызвать 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

Ответов (3)

Решение

@FryHard FirstOrDefault будет работать, но помните, что он возвращает null, если ничего не найдено. Этот код не протестирован, но должен быть близок к тому, что вы хотите:

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

if (app == null)
    return;

SetForegroundWindow(app.MainWindowHandle);

Как не использовать , Count() как ICR говорит. Count() будет перебирать, IEnumerable чтобы выяснить, сколько в нем элементов. В этом случае снижение производительности может быть незначительным, поскольку процессов не так много, но это плохая привычка. Используйте только Count() тогда, когда ваш запрос интересует только количество результатов. Count почти никогда не бывает хорошей идеей.

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

var app = apps.FirstOrDefault();

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

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

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