Dynamic linq Building Expression

前端 未结 5 2054
失恋的感觉
失恋的感觉 2021-01-06 19:14

I need to create a dynamic linq expression for a dynamic search.The basic search is working but it fails to work with collection. I am able to get the book\'s title and auth

5条回答
  •  南笙
    南笙 (楼主)
    2021-01-06 20:13

    Based on your description I'm not sure that you need Expression. Creating an Expression with a complex object model is quite difficult. Do you really need to create dynamic expression or you simply need to create a dynamic query? If the object model is fixed then you don't need Expression.

    I suggest first of all to clean your object model:

    • Rename the Books class to Book (this class represents a Book not a list of books)
    • Rename property Page to Pages (this property returns a list of pages)

    Now you can write a dynamic where using just LINQ and one or more helper functions one for each property that you need to search. For example to search for Heading you can write:

            private static bool SearchByHeading(Book b, string heading)
            {
                if (string.IsNullOrEmpty(heading))
                    return true;
                else
                    return b.Pages.Any(p => p.Heading == heading);
            }
    

    Here you can also see why your previous code didn't work. The expression to search for a given Heading is book.Pages.Any(p => p.Heading == x) and not book.Pages.Heading == x.

    In any case given one or more functions like this you can rewrite your code with something like:

    using System.Collections.Generic;
    using System.Linq;
    
    namespace XMLStorageAndFilter
    {
        public class Book
        {
            public Book()
            {
                Pages = new List();
            }
            public string Title { get; set; }
            public Author Author { get; set; }
            public List Pages { get; set; }
        }
        public class Author
        {
            public string FirstName { get; set; }
        }
        public class Page
        {
            public string Heading { get; set; }
        }
    
        public class Program2
        {
            static void Main()
            {
                Page page = new Page();
                page.Heading = "Heading1";
                Book bok = new Book();
                bok.Title = "Title1";
                bok.Author = new Author() { FirstName = "FirstName1" };
                bok.Pages.Add(page);
                List testList = new List();
                testList.Add(bok);
    
                var searchResult = Search(testList, 
                    title: "Title1",
                    author: "FirstName1",
                    heading: "Heading1");
            }
    
            private static IEnumerable Search(IEnumerable books, string author = null, string title = null, string heading = null)
            {
                return books
                    .Where((b) => SearchByAuthor(b, author))
                    .Where((b) => SearchByHeading(b, heading))
                    .Where((b) => SearchByTitle(b, title))
                    .ToList();
            }
    
            private static bool SearchByAuthor(Book b, string author)
            {
                if (string.IsNullOrEmpty(author))
                    return true;
                else
                    return b.Author.FirstName == author;
            }
    
            private static bool SearchByTitle(Book b, string title)
            {
                if (string.IsNullOrEmpty(title))
                    return true;
                else
                    return b.Title == title;
            }
    
            private static bool SearchByHeading(Book b, string heading)
            {
                if (string.IsNullOrEmpty(heading))
                    return true;
                else
                    return b.Pages.Any(p => p.Heading == heading);
            }
        }
    }
    

    I have skipped search values when null or empty, just an example. This code has also the advantage that is verified at compile time.

提交回复
热议问题