Requête Linq - "Où" sur la liste Où la propriété reflète contient du texte / valeur

c# expression-trees linq

Question

Je voudrais construire une fonction où l'utilisateur pourrait rechercher si certaines propriétés de la liste contiennent de la valeur

Disons que nous aurons une liste et que la société sera définie comme une classe avec des propriétés telles que:

public class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string CompanyAddress1 { get; set; }
    public string CompanyPostCode { get; set; }
    public string CompanyCity { get; set; }
    public string CompanyCounty { get; set; }
}

Maintenant - idéalement, j'aimerais avoir cette fonction avec ces paramètres

List<Company> FilterCompanies(List<Company> unfilteredList, string fieldToQueryOn, string query)
{
    // linq  version what ideally would like to archeve
    return unfilteredList.Where(x => x."fieldToQueryOn".ToString().ToLower().Contains(query.ToLower())).ToList();
}

et appelez:

var variable = FilterCompanies(NotNullFilledUnfilteredList, "CompanyCity", "New York")

J'ai essayé de suivre le didacticiel sur docs.microsoft.com et c'est facile, mais je n'ai aucune idée de la façon d'étendre cette solution avec une réflexion sur Type et de l'utiliser dans un arbre d'expression.

Réponse acceptée

Vous pouvez utiliser Type.GetProperty pour rechercher une propriété par son nom en utilisant une réflexion, puis utiliser GetValue pour récupérer la valeur:

List<Company> FilterCompanies(List<Company> list, string propertyName, string query)
{
    var pi = typeof(Company).GetProperty(propertyName);

    query = query.ToLower();
    return list
        .Where(x => pi.GetValue(x).ToString().ToLower().Contains(query))
        .ToList();
}

Vous devriez probablement ajouter un peu de gestion des erreurs au cas où quelqu'un utiliserait une propriété invalide. Par exemple, vous pouvez faire (pi?.GetValue(x) ?? string.Empty).ToString().ToLower()… être du bon côté.

query.ToLower() également déplacé la query.ToLower() de l'expression lambda pour m'assurer qu'elle ne s'exécute qu'une fois. Vous pouvez également essayer d'autres méthodes peu sensibles à la casse pour vérifier si query est une sous-chaîne de la valeur afin d'éviter de devoir convertir une chaîne. Consultez la question " Non sensible à la casse 'Contient (chaîne)" - pour plus d'informations.

Btw. si vous êtes généralement intéressé par l'exécution de requêtes dynamiques, consultez LINQ dynamique .


Réponse populaire

Génériques et lambda:

namespace WhereTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var companies = new[] { new Company { Id = 1, Name = "abc" }, new Company { Id = 2, CompanyAddress1 = "abc" } };
            foreach (var company in FilterCompanies(companies, "abc", x => x.Name, x => x.CompanyCity))
            {
                Console.WriteLine(company.Id);
            }
        }

        static List<Company> FilterCompanies(IEnumerable<Company> unfilteredList, string query, params Func<Company, string>[] properties)
        {
            return unfilteredList.Where(x => properties.Any(c => c.Invoke(x) == query)).ToList();
        }
    }

    public class Company
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string CompanyAddress1 { get; set; }
        public string CompanyPostCode { get; set; }
        public string CompanyCity { get; set; }
        public string CompanyCounty { get; set; }
    }
}

Avantages: pas de réflexion, code fortement typé.



Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow