Linq para objetos - selecione o primeiro objeto
-
08-06-2019 - |
Pergunta
Não sei quase nada sobre linq.
Eu estou fazendo isto:
var apps = from app in Process.GetProcesses()
where app.ProcessName.Contains( "MyAppName" ) && app.MainWindowHandle != IntPtr.Zero
select app;
O que me dá todos os processos em execução que atendem a esses critérios.
Mas não sei como conseguir o primeiro.Os exemplos que posso encontrar na rede parecem implicar que tenho que fazer isso
var matchedApp = (from app in Process.GetProcesses()
where app.ProcessName.Contains( "MyAppName" ) && app.MainWindowHandle != IntPtr.Zero
select app).First();
o que me parece um tanto feio e também lança uma exceção se não houver processos correspondentes.Existe uma maneira melhor?
ATUALIZAR
Na verdade, estou tentando encontrar o primeiro item correspondente e ligo SetForegroundWindow
nele
Eu descobri essa solução, que também me parece feia e horrível, mas melhor que a anterior.Alguma ideia?
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
Solução
@FryHard FirstOrDefault funcionará, mas lembre-se de que retornará nulo se nenhum for encontrado.Este código não foi testado, mas deve estar próximo do que você deseja:
var app = Process.GetProcesses().FirstOrDefault(p => p.ProcessName.Contains("MyAppName") && p.MainWindowHandle != IntPtr.Zero);
if (app == null)
return;
SetForegroundWindow(app.MainWindowHandle);
Outras dicas
Fazer não usar Count()
como diz o ICR. Count()
irá iterar através do IEnumerable
para descobrir quantos itens ele possui.Nesse caso, a penalidade de desempenho pode ser insignificante, pois não há muitos processos, mas é um mau hábito adquirir.Use apenas Count()
quando sua consulta está interessada apenas no número de resultados. Count
quase nunca é uma boa ideia.
Existem vários problemas com a resposta de FryHard.Primeiro, por causa execução atrasada, você acabará executando a consulta LINQ duas vezes, uma vez para obter o número de resultados e outra para obter o FirstOrDefault
.Em segundo lugar, não há razão alguma para usar FirstOrDefault
depois de verificar a contagem.Como ele pode retornar nulo, você nunca deve usá-lo sem verificar se há nulo.Ou faça apps.First().MainWindowHandle
ou:
var app = apps.FirstOrDefault();
if (app != null)
SetForegroundWindow(app.MainWindowHandle);
É por isso que a melhor solução é a de Mark, sem dúvida.É a maneira mais eficiente e estável de usar o LINQ para conseguir o que deseja.
Supondo que em seu primeiro exemplo, apps seja um IEnumerable, você pode usar as propriedades .Count e .FirstOrDefault para obter o único item que deseja passar para 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 );
}