Список поиска с использованием linq динамически

#c# #linq

#c# #linq

Вопрос:

Я хочу создать функцию, в которой я могу запускать динамические запросы linq.

Вместо того, чтобы создавать отдельный запрос linq для каждого поиска, я хочу создать одну динамическую функцию, куда я могу передать имя столбца, я хочу выполнить поиск.

Пока что мой динамический запрос linq возвращает строковое значение в параметре поиска, и я не могу получить идентификатор в списке

 using System.Collections.Generic;
using System.Linq;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Author> authors = new List<Author>
            {
                new Author {Id = 1, Name = "Mahesh Chand", Book = "ADO.NET Programming", Price = 49.95},
                new Author {Id = 2, Name = "Neel Beniwal", Book = "Jump Ball", Price = 19.95},
                new Author {Id = 3, Name = "Chris Love", Book = "Practical PWA", Price = 29.95}
            };
            // Add more items to the list  
            authors.Add(new Author { Id = 4, Name = "Jack", Book = "Graphics with GDI ", Price = 49.95});
            authors.Add(new Author { Id = 5, Name = "Jack", Book = "Mastering C#", Price = 54.95});
            authors.Add(new Author { Id = 6, Name = "Jack", Book = "Jumpstart Blockchain", Price = 44.95});

            var nameFound = SearchColumn(authors, "Name", "Jack");

        }

        public class Author
        {
            public int Id;
            public string Name;
            public string Book;
            public double Price;
        }
        public class MatchFound
        {
            public int Id;
            public string Column;
            public string MatchString;
        }

        private static List<MatchFound> SearchColumn(List<Author> authorList, string column, string searchCharacter)
        {
            var result = new List<MatchFound>();
            // linq query #1
            var separaList = authorList.Select(l => column).ToList();
            foreach (var row in separaList)
            {
                if (row == searchCharacter)
                {
                    var temp = new MatchFound()
                    {
                        Id = row.Id, // cannot reach ID, because linq Query #1 does not include ID
                        Column = column,
                        MatchString = row
                    };

                    result.Add(temp);
                }
            }
            return resu<
        }
    }
}
 

Ответ №1:

var separaList = authorList.Select(l => column).ToList(); этот код не очень хорош, потому что вы выбираете то, что отправляете в функцию, если вы отправляете Name , будет выбрано шесть раз Name или если вы отправляете Other , будет выбрано шесть раз Other .

Если я правильно понял, вы можете добиться этого с помощью отражения, поэтому функция SearchColumn будет выглядеть так :

 private static List<MatchFound> SearchColumn(List<Author> authorList, string column, string searchCharacter)
{
    // linq query #1
    FieldInfo fieldInfo = typeof(Author).GetField(column, BindingFlags.Public | BindingFlags.Instance);
    return authorList
        .Where(a => fieldInfo.GetValue(a).ToString() == searchCharacter)
        .Select(a => new MatchFound
        {
            Id = a.Id,
            Column = column,
            MatchString = searchCharacter
        }).ToList();
}
 

ПРИМЕЧАНИЕ: если вы меняете Author поля на свойства, используйте getProperty вместо getField .

Для тестирования :

 static void Main(string[] args)
{
    List<Author> authors = new List<Author>
    {
        new Author {Id = 1, Name = "Mahesh Chand", Book = "ADO.NET Programming", Price = 49.95},
        new Author {Id = 2, Name = "Neel Beniwal", Book = "Jump Ball", Price = 19.95},
        new Author {Id = 3, Name = "Chris Love", Book = "Practical PWA", Price = 29.95}
    };
    // Add more items to the list  
    authors.Add(new Author { Id = 4, Name = "Jack", Book = "Graphics with GDI ", Price = 49.95 });
    authors.Add(new Author { Id = 5, Name = "Jack", Book = "Mastering C#", Price = 54.95 });
    authors.Add(new Author { Id = 6, Name = "Jack", Book = "Jumpstart Blockchain", Price = 44.95 });

    var nameFound = SearchColumn(authors, "Name", "Chris Love");
    Console.WriteLine($"Id : {nameFound.First().Id}");

    var bookFound = SearchColumn(authors, "Book", "Mastering C#");
    Console.WriteLine($"Id : {bookFound.First().Id}");
}
 

Результат

 Id : 3
Id : 5
 

Я надеюсь, что вы найдете это полезным.

Комментарии:

1. Мне нравится использовать GetPropertyOrField и метод расширения на MemberInfo : object GetValue(this MemberInfo ...) , который обрабатывает либо.

2. У меня такое чувство, что вы правы, но я не могу понять, как использовать getProperty при изменении полей на свойства

3. @InternetEngineer это как PropertyInfo propertyInfo = typeof(Author).GetProperty(column, BindingFlags.Public | BindingFlags.Instance);

Ответ №2:

Просто чтобы пойти другим путем, вот как вы можете использовать Expression деревья для построения лямбда-метода для Where метода:

 static List<MatchFound> SearchColumn(List<Author> authorList, string column, string searchCharacter) {
    // a
    var aParm = Expression.Parameter(typeof(Author), "a");
    // a.{column}
    var aColumnExpr = Expression.PropertyOrField(aParm, column);
    // a.{column} == searchCharacter
    var whereLambdaBody = Expression.MakeBinary(ExpressionType.Equal, aColumnExpr, Expression.Constant(searchCharacter));
    // a => a.{column} == searchCharacter
    var whereLambda = Expression.Lambda<Func<Author, bool>>(whereLambdaBody, aParm);
    var whereFn = whereLambda.Compile();

    return authorList.Where(whereFn).Select(a => new MatchFound { Id = a.Id, Column = column, MatchString = searchCharacter }).ToList();
}
 

ПРИМЕЧАНИЕ: Компиляция whereLambda выполняется медленно, было бы полезно кэшировать результат, если бы вы делали это часто, отражение с GetValue , вероятно, быстрее, пока authorList не станет достаточно большим. Однако этот метод также работает с LINQ для баз данных, просто не компилируя whereLambda и вместо этого передавая Expression into Where .