#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
.