pensum
pensum

Reputation: 1019

(C#) LINQ — Cannot find any result with method .Contains()

I have two queries for searching Authors by names and Books by title. The first one is working as expected, which is looking if any authors' name contains my input. For some reason, I cannot do the same with the books' title. I receive an error saying I cannot act on char when I know it is a string...

The only difference between them is that I am using a List<string> Names and a string Title


Query by `Author names` (working)

author = from book in Serialisation.Books
         where book.Author.Names.Any(author => author.Contains(InputBook.Text))
         select book;

When I hover on author => author it tells me it's a string parameter. The property Names is a List<string> Names because some books may have 2 authors. I am capable of finding any authors' names that corresponds to a search with only one letter.

For example : « M » outputs => Margaret Atwood


Query by `Book titles` (not working)

book = from book in Serialisation.Books
       where book.Title.Any(x => x.Contains(InputBook.Text))
       select book;

Here, when I hover on x => x it tells me it's a char parameter, therefore I cannot use the method .Contains()...

The only solution I got is to write this instead :

book = from book in Serialisation.Books
       where book.Title == InputBook.Text
       select book;

Which of course is not what I want. I don't know what to change in order to make it work..

EDIT: I have tried book.Title.Contains(InputBook.Text) and I get an error later telling me I cannot get null value when converting the output.ToList()


Class Book

public class Book 
{
    public string Title { get; set; }
    public Author Author { get; set; }
    // my other class Author is simply a list of names. 
    // I need it to override the method ToString() so that 
    // when there is two authors for the same book, I only have 
    // one string to look into for my query.
}

Upvotes: 0

Views: 800

Answers (2)

tmaj
tmaj

Reputation: 35075

where book.Title.Any(x => x.Contains(searchTerm))

would not compile because you're deconstructing Title into a collection of chars. It says: give me all books that have a title for which each character contains my search term.

I think you want

where book.Title.Contains(searchTerm))

This says: give me all books with a title which contains the search term.

From your comments it seems that there are books with titles which are null. In this case wee need to guard against that, otherwise Title.Contains will throw NullReferenceException

where !string.IsNullOrEmpty(book.Title) &&
               book.Title.Contains(searchTerm)

This says: give me all books with a title which is not null and is not empty and contains searchTerm.

Finally, you may want to ensure that the search is case-insensitive.

where !string.IsNullOrEmpty(book.Title) &&
               book.Title.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase)

Test

string searchTerm = "Adventures";
var books = new [] { 
    new Book{Title = "Adventures in Code"},
    new Book{Title = "My adventures in Oz"},
    new Book{Title = "About Linq"},
    new Book{Title = null} // no title
    };
var found = from book in books
        where !string.IsNullOrEmpty(book.Title) &&
               book.Title.Contains(searchTerm, StringComparison.InvariantCultureIgnoreCase)
        select book;
foreach( var b in found ) Console.WriteLine(b.Title);

Output

Adventures in Code
My adventures in Oz

Upvotes: 1

Franck
Franck

Reputation: 4440

Your property Title is a string and in most languages including C#, string is in fact an array of char

The linq query Any is iterating on the array so since the property is a string which in itself is a char[] i check if Any or the char match the predicate.

What you are looking for is comparing the string itself if it contains the other string. therefor you need to use :

where book.Title.Contains(InputBook.Text)

Upvotes: 1

Related Questions