Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq Results of Where to Object Collection

Tags:

c#

.net

linq

I've got a problem that I can work around, but I feel like there should be a solution within Linq that I'm just not seeing.

So I have two classes, a detail record class and a collection of those classes:

public class ItemDetail
{
    public string Name {get;set;}
    public int? Id {get;set;}
}

public class ItemDetailCollection : List<ItemDetail>
{
}

Now, I can fill up those objects using my repository layer without a problem, and query the data to get the subset of records I want.

var items = Repository.GetItemCollection();
var reportItemCollection = items.Where(x=>x.Id.HasValue);

This is all fine and dandy. However, the reportItemCollection is an IEnumberable<ItemDetail>, and what I really want is a new ItemDetailCollection.

Of course, I could create a new collection and add the query range, but I feel like there is a way to automatically populate the result set as the specific collection type. I've tried adding the following and only receive the results as NULL:

var reportItemCollection = items.Where(x=>x.Id.HasValue) as ItemDetailCollection;

And trying .Cast<ItemDetailCollection>() does not work either. Finally, I've tried

var reportItemCollection = items.Where(x=>x.Id.HasValue).Select(result => new ItemDetailCollection(){ result });

but this only gives me an IEnumerable<ItemDetailCollection>.

Any thoughts?

like image 509
brenton Avatar asked Dec 12 '22 07:12

brenton


2 Answers

The only way is to actually construct the collection, using the constructor for List<T>:

public class ItemDetailCollection : List<ItemDetail>
{
    public ItemDetailCollection(IEnumerable<ItemDetail> items)
        : base(items) { }
}

And

var reportItemCollection = new ItemDetailCollection(
    items.Where(x=>x.Id.HasValue)
);

You can't cast an IEnumerable<T> to a subclass like ItemDetailCollection, due to the rules of covariance/contravariance (see here, for example: http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx).

like image 117
McGarnagle Avatar answered Dec 26 '22 13:12

McGarnagle


I would solve this the same way that LINQ solves it for List<T>: create a ToItemDetailCollection extension method

static ItemDataCollection ToItemDataCollection(this IEnumerable<ItemDetail> e) {
  return new ItemDataCollection(e);
}

Then you can just append this to any query

var reportItemCollection = items
  .Where(x=>x.Id.HasValue)
  .ToItemDataCollection();

On a separate note I would question why you are deriving from List<T> at all. It offers no virtual methods to override and hence there is no possibility of customization. Using this over List<ItemDetail> everywhere will just cause a lot of pain points like this one.

like image 29
JaredPar Avatar answered Dec 26 '22 11:12

JaredPar