As expressões lambda, como procurar dentro de um objeto?
Pergunta
Eu estou começando a amar expressões lambda, mas eu estou lutando para passar essa parede:
public class CompanyWithEmployees {
public CompanyWithEmployees() { }
public Company CompanyInfo { get; set; }
public List<Person> Employees { get; set; }
}
A minha pesquisa:
List<CompanyWithEmployees> companiesWithEmployees = ws.GetCompaniesWithEmployees();
CompanyWithEmployees ces = companiesWithEmployees
.Find(x => x.Employees
.Find(y => y.PersonID == person.PersonID));
Então, eu quero pegar o objeto "CompanyWithEmployees" que têm essa pessoa (funcionário) que eu estou procurando, mas eu estou recebendo " Não é possível implícita convertido 'Pessoa' Para 'bool') " o que é correto, mas se eu não estou passando o objeto Pessoa, como pode o encontrar primeiro executa?
Solução
Porque você quer verificar se há existência, talvez tente:
ces = companiesWithEmployees
.Find(x => x.Employees
.Find(y => y.ParID == person.ParID) != null);
Este irá verificar se há qualquer Person
com o mesmo ParID
; Se você quer dizer a mesma instância Person
(referência), então Contains
deve bastar:
ces = companiesWithEmployees
.Find(x => x.Employees.Contains(person));
Outras dicas
Find()
retorna o objeto encontrado. Use Any()
apenas para verificar se a expressão é verdadeiro para qualquer elemento.
var ces = companiesWithEmployees
.Find(x => x.Employees
.Any(y => y.PersonID == person.PersonID));
ces = companiesWithEmployees
.First(x => x.Employees.Any(p=>p.PersonID == person.PersonID));
ces = companiesWithEmployees.Find( x => x.Employees.Find(...) );
.Find
retornos único objeto, x.Employees.Find(..)
retornos Person
.
.Find
espera o parâmetro boolean (ou seja. O resultado de condições), é por isso que há um erro de compilador que diz Cannot implicit convert 'Person' To 'bool'
.Where
pode retornar vários objetos, daí possível percorrer todos lista.
usar uma combinação de .Where
e .Any
no seu caso.
o seguinte código irá ilustrar a diferença entre .Where
, .Find
e .Any
:
public partial class Form2 : Form {
public Form2() {
InitializeComponent();
var companiesWithEmployees = new List<CompanyWithEmployees>() {
new CompanyWithEmployees {
CompanyInfo = new Company { CompanyName = "Buen" },
Employees = new List<Person>() {
new Person { PersonID = 1976, PersonName = "Michael" },
new Person { PersonID = 1982, PersonName = "Mark" },
new Person { PersonID = 1985, PersonName = "Matthew" },
new Person { PersonID = 1988, PersonName = "Morris" }
}
},
new CompanyWithEmployees {
CompanyInfo = new Company { CompanyName = "Muhlach" },
Employees = new List<Person>() {
new Person { PersonID = 1969, PersonName = "Aga" },
new Person { PersonID = 1971, PersonName = "Nino" },
new Person { PersonID = 1996, PersonName = "Mark" }
}
},
new CompanyWithEmployees {
CompanyInfo = new Company { CompanyName = "Eigenmann" },
Employees = new List<Person>() {
new Person { PersonID = 1956, PersonName = "Michael" },
new Person { PersonID = 1999, PersonName = "Gabby" }
}
}
};
// just explicitly declared the types (instead of var) so the intent is more obvious
IEnumerable<CompanyWithEmployees> whereAreMichaels = companiesWithEmployees
.Where(cx => cx.Employees.Any(px => px.PersonName == "Michael"));
string michaelsCompanies = string.Join(", ", whereAreMichaels
.Select(cx => cx.CompanyInfo.CompanyName).ToArray());
MessageBox.Show("Company(s) with employee Michael : " + michaelsCompanies);
Person findAga = companiesWithEmployees
.Find(company => company.CompanyInfo.CompanyName == "Muhlach")
.Employees.Find(person => person.PersonName == "Aga");
if (findAga != null)
MessageBox.Show("Aga's ID : " + findAga.PersonID.ToString());
}
}
class CompanyWithEmployees {
public Company CompanyInfo { get; set; }
public List<Person> Employees { get; set; }
}
class Company {
public string CompanyName { get; set; }
}
class Person {
public int PersonID { get; set; }
public string PersonName { get; set; }
}
Isso é porque você não especificou uma expressão Find legítima para o seu nível mais alto Find.
Vou mostrar aqui:
ces = companiesWithEmployees
.Find (x => x.Employees.Find(y => y.ParID == Person.ParID) /*condition is missing here*/);
Então, o que é a condição para a sua descoberta inicial?
A única mais fácil seria
ces = companiesWithEmployees.FirstOrDefault(x =>
x.Employees.Any(y => y.PersonID == person.ParID));
sem qualquer verificação nulo