2008-08-11 15 views
10

No sé casi nada sobre linq.Linq a los objetos: seleccione el primer objeto

que estoy haciendo esto:

var apps = from app in Process.GetProcesses() 
    where app.ProcessName.Contains("MyAppName") && app.MainWindowHandle != IntPtr.Zero 
    select app; 

Lo cual me lleva todos los procesos en ejecución que coinciden con ese criterio.

Pero no sé cómo obtener la primera. Los ejemplos que puedo encontrar en la red parece dar a entender que tengo que hacer esto

var matchedApp = (from app in Process.GetProcesses() 
    where app.ProcessName.Contains("MyAppName") && app.MainWindowHandle != IntPtr.Zero 
    select app).First(); 

que me parece un poco feo, y también produce una excepción si no hay procesos de casación. ¿Hay una mejor manera?

ACTUALIZACIÓN

realidad estoy tratando de encontrar el primer elemento coincidente, y llamar a SetForegroundWindow en él

Yo he llegado con esta solución, que también me parece feo y horrible, pero mejor que arriba ¿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 

Respuesta

19

@FryHard FirstOrDefault funcionará, pero recuerde que devuelve null si no se encuentra ninguno. Este código no se ha probado, pero debe estar cerca de lo que quiere:

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

if (app == null) 
    return; 

SetForegroundWindow(app.MainWindowHandle); 
+0

¿cómo lo pones como una consulta y no como un método de extensión? –

+2

@Quintin no existe una sintaxis de "palabra clave" para FirstOrDefault: debe usar el método de extensión. –

+1

Bueno, podrías usar '(query) .FirstOrDefault()' pero el método de extensión de sentax es más fácil de leer imo –

1

Suponiendo que en su primer ejemplo Apps es un IEnumerable se podría hacer uso de las propiedades y .count .FirstOrDefault para obtener el único elemento 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); 
} 
+1

como se indica en otra parte, esto elimina los beneficios de linq (ejecución retrasada) y FirstOrDefault es redundante con un recuento de –

2

Haz no uso Count() como ICR dice. Count() iterará a través del IEnumerable para calcular cuántos elementos tiene. En este caso, la penalización de rendimiento puede ser insignificante, ya que no hay muchos procesos, pero es un mal hábito entrar. Solo use Count() cuando su consulta solo está interesada en el número de resultados.Count casi nunca es una buena idea.

Hay varios problemas con la respuesta de FryHard. En primer lugar, debido a delayed execution, terminará ejecutando la consulta LINQ dos veces, una para obtener el número de resultados y otra para obtener el FirstOrDefault. Segundo, no hay ninguna razón para usar FirstOrDefault después de verificar el recuento. Como puede devolver nulo, nunca debes usarlo sin verificar null. O haces o apps.First().MainWindowHandle:

var app = apps.FirstOrDefault(); 

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

Esta es la razón por la mejor solución es Marcos, sin lugar a dudas. Es la forma más eficiente y estable de usar LINQ para obtener lo que desea.

Cuestiones relacionadas