Linq to object — выбрать первый объект
-
08-06-2019 - |
Вопрос
Я почти ничего не знаю о 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
Решение
@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()
как говорит МЦР. 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 );
}