Linq a objetos: seleccione el primer objeto
-
08-06-2019 - |
Pregunta
No sé casi nada sobre linq.
Estoy haciendo esto:
var apps = from app in Process.GetProcesses()
where app.ProcessName.Contains( "MyAppName" ) && app.MainWindowHandle != IntPtr.Zero
select app;
Lo que me proporciona todos los procesos en ejecución que coinciden con ese criterio.
Pero no sé cómo conseguir el primero.Los ejemplos que puedo encontrar en la red parecen implicar que tengo que hacer esto.
var matchedApp = (from app in Process.GetProcesses()
where app.ProcessName.Contains( "MyAppName" ) && app.MainWindowHandle != IntPtr.Zero
select app).First();
lo que me parece algo feo y también genera una excepción si no hay procesos coincidentes.¿Existe una mejor manera?
ACTUALIZAR
De hecho, estoy tratando de encontrar el primer elemento coincidente y llamar SetForegroundWindow
en eso
Se me ocurrió esta solución, que también me parece fea y horrible, pero mejor que la anterior.¿Algunas ideas?
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
Solución
@FryHard FirstOrDefault funcionará, pero recuerde que devuelve nulo si no se encuentra ninguno.Este código no está probado pero debería ser similar a lo que desea:
var app = Process.GetProcesses().FirstOrDefault(p => p.ProcessName.Contains("MyAppName") && p.MainWindowHandle != IntPtr.Zero);
if (app == null)
return;
SetForegroundWindow(app.MainWindowHandle);
Otros consejos
Hacer no usar Count()
como dice ICR. Count()
iterará a través del IEnumerable
para saber cuántos elementos tiene.En este caso, la penalización en el rendimiento puede ser insignificante ya que no hay muchos procesos, pero es un mal hábito.Uso único Count()
cuando tu consulta solo esta interesada en el número de resultados. Count
casi nunca es una buena idea.
Hay varios problemas con la respuesta de FryHard.Primero, debido a ejecución retrasada, terminará ejecutando la consulta LINQ dos veces, una para obtener el número de resultados y otra para obtener el FirstOrDefault
.En segundo lugar, no hay razón alguna para utilizar FirstOrDefault
después de comprobar el recuento.Dado que puede devolver nulo, nunca debes usarlo sin verificar si es nulo.O lo haces apps.First().MainWindowHandle
o:
var app = apps.FirstOrDefault();
if (app != null)
SetForegroundWindow(app.MainWindowHandle);
Por eso la mejor solución es la de Mark, sin lugar a dudas.Es la forma más eficiente y estable de utilizar LINQ para conseguir lo que desea.
Suponiendo que en su primer ejemplo las aplicaciones son IEnumerable, podría utilizar las propiedades .Count y .FirstOrDefault para obtener el elemento único que desea pasar a 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 );
}