2

I have a function that returns an array of objects. The problem is, the objects can be one of three different types. I am trying to break these objects into arrays of the different custom types.

For example:

var collection = something.ReturnObjArray();
var Details = collection.Where(a => a is DetailItem);
var Addenda = collection.Where(a => a is AddendaItem);

If i do the above and try to access the data in a foreach loop to put the Addenda in a collection within the Detail Items:

foreach (var addendaItem in Addenda)
{
    var detailItem = Details.Single(d => d.DetailAddendaKey == addendaItem.Key);
    detailItem.Addenda.Add(addendaItem);
}

I get errors like :

'object' does not contain a definition for 'DetailAddendaKey' and no extension method 'DetailAddendaKey' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

Among others. If i try and change the var for Details and Addenda to:

IEnumerable<DetailItem> Details = collection.Where(a => a is DetailItem);
IEnumerable<AddendaItem> Addenda = collection.Where(a => a is AddendaItem);

I get past the error above, but now get:

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<object>' to 'System.Collections.Generic.IEnumerable<MyNameSpace.DetailItem>'. An explicit conversion exists (are you missing a cast?)

Any ideas what I need to do?

Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
SpaceCowboy74
  • 1,367
  • 1
  • 23
  • 46

2 Answers2

7

Use OfType<T>.

Filters the elements of an IEnumerable based on a specified type.

Example:

IEnumerable<DetailItem> Details = collection.OfType<DetailItem>();
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
1

I suspect that this sentence returns an object of type object[] (an object array):

var collection = something.ReturnObjArray();

object doesn't have the whole properties!

That's why Details.Single(d => d.DetailAddendaKey == addendaItem.Key) complains about that d doesn't have a property DetailAddendaKey.

You need to do this:

var Details = collection.Where(a => a is DetailItem).Cast<DetailItem>();
var Addenda = collection.Where(a => a is AddendaItem).Cast<AddendaItem>();

Or as @Mark Byers suggested (which is an abbreviation of above sample):

var Details = collection.OfType<DetailItem>();
var Addenda = collection.OfType<AddendaItem>();

This is downcasting all items in the IEnumerable<object> to DetailItem or AddendaItem, meaning that you'll have an IEnumerable<DetailItem> and IEnumerable<AddendaItem> after all!

Then, the next sentences will compile and work as you expect.

Note

OfType<T>() should be a better choice since your approach of using is operator and later calling Cast<T>() is downcasting twice each object in the object array.

Check this other question and its answers for more info about is operator and its behavior:

Community
  • 1
  • 1
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206