6

I have a class like this:

public class MailMessage
{
    public string From {get; set; };
    public string To {get; set; };   
    public ICollection<Attachment> Attachments { get; set; }
}

public class Attachment
{
  public string Name {get; set;} 
  public byte[] Content {get;set;}   

}

I would like to get all attachments in Attachments collection whose name ends with .pdf.

I tried the following:

List<MailMessage> list = new List<MailMessage>();
List<attachment> pdfAttachmentsCollection = list.Where(x => x.Attachments
                               .Where(attachment => 
                                attachment.Name.EndsWith(".pdf")).Select(y => y.Content));

However, this doesnt work. Any suggestions. It gives error:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable ' to 'bool'

5
  • 1
    Possible duplicate of Difference Between Select and SelectMany Commented Nov 23, 2018 at 4:02
  • 1
    That error is probably coming from the first where since it isn't a boolean expression for the predicate that is given. Commented Nov 23, 2018 at 4:09
  • 2
    var pdfAttachmentsCollection = list.SelectMany(x => x.Attachments.Where(a => a.Name.ToLower().EndsWith(".pdf"))).ToList(); Commented Nov 23, 2018 at 4:11
  • 1
    I'd suggest starting with list.SelectMany(x => x.Attachments). The rest is standard Where stuff that you'll work out easily. Jim's approach will work equally well. Commented Nov 23, 2018 at 4:12
  • 1
    Better for case-insensitive check: Name.EndsWith(".pdf", StringComparison.InvariantCultureIgnoreCase) Commented Nov 23, 2018 at 4:21

1 Answer 1

12

A couple issues:

  • You need to SelectMany from the MailMessage object to get all attachments in a single collection
  • You're selecting y.Content which is byte[] but trying to get a list of Attachment
  • LINQ returns IEnumerables, not Lists

Rewritten, you probably want to do something like:

List<MailMessage> list = new List<MailMessage>();
IEnumerable<Attachment> pdfAttachmentsCollection = 
    list.SelectMany(message => 
        message.Attachments
            .Where(attachment => attachment.Name.EndsWith(".pdf")));

This is also a good candidate to write as a query expression:

IEnumerable<Attachment> pdfAttachmentsCollection = 
    from message in list 
    from attachment in message.Attachments
    where attachment.Name.EndsWith(".pdf")
    select attachment;

Both of these do the same thing, just with different syntax.

If you want this as a List<Attachment> you can also do .ToList() at the end of either query. As an IEnumerable, it won't be evaluated until you start iterating through it (and depending on how you use it, you might never have the full collection in memory at any time). However, if you do multiple iterations or operations on it, it'll cause it to be evaluated multiple times -- so in those cases .ToList() makes sense for sure.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.