0

Given this linqpad code:

interface I {}
public class A : I {}
public class B : A {}
void Main()
{
    var i = new List<I>(new I[] { new A(), new B(), new A(), new B() });
    i.GroupBy(_ => _.GetType()).Select(_ => _.ToArray()).Dump();
}

What is the most efficient way to convert these items into IEnumerables of the actual derived types?

I have a method with signature DoStuffToArray<T>(IEnumerable<T> items)
I need to call it dynamically once for each of different types in the list i. It's a library method that needs to be called with the derived types, not the interface.

I have managed to get two typed arrays using this method, is there a better way?

var typeGroup = i.GroupBy(_ => _.GetType()).ToArray();
var arrays = typeGroup.Select(_ => Array.CreateInstance(_.Key, _.Count())).ToArray();   
for (int ai = 0; ai < typeGroup.Length; ai++)
{
    var grouping = typeGroup[ai].ToArray();
    int index = 0;
    Array.ForEach(grouping, _ => arrays[ai].SetValue(_, index++));
}
arrays.Dump("typed arrays");
Jim
  • 14,952
  • 15
  • 80
  • 167

2 Answers2

1

You are looking for OfType<T>().

var i = new List<I>(new I[] { new A(), new B(), new A(), new B() });
var ayes = i.OfType<A>();
var bees = i.OfType<B>(); 

DoStuffToArray(ayes);
DoStuffToArray(bees);

Live example: http://rextester.com/HQWP13863

Jamiec
  • 133,658
  • 13
  • 134
  • 193
  • I will not know each of the types in the array ahead of time. I want to do the cast dynamically. Basically I need an OfType(Type type) extension method. Perhaps I can do it with F# :-) – Jim Mar 04 '15 at 12:43
  • If you dont know the type at compile time, you probably shouldnt be using generics. – Jamiec Mar 04 '15 at 12:46
  • I was thinking about a pattern where I inject IEnumerable using a DI container, thus 'dynamically' creating an implementation per type, I am not sure it solves the problem though... – Jim Mar 04 '15 at 12:46
  • I know, the pattern is probably broken. Ultimately I think I need to fix the library method to take a type argument. – Jim Mar 04 '15 at 12:48
  • The reason I got here, is that the DI container is injecting instance handlers for each type of instance, and the handlers are producing results into a cached calculation database. I am then persisting the calculations into different tables depending on their type. The types are all supplied by the container. I could add a line of code for each injected calculation type, but that seems dirty. – Jim Mar 04 '15 at 14:07
  • I think this is the best answer I will get, it's basically not possible without a lot of runtime hacks. I need to get the code for bulk insert from github, and add a method that takes a type argument, or get the code for entity framework and add support for interfaces... :-) – Jim Mar 05 '15 at 03:34
0

How about:

List<I> i = new List<I>(new I[] {new A(), new B(), new A(), new B()});

var types = i.Select(item => item.GetType()).Distinct();

foreach (var instances in types.Select(type => i.Where(item =>item.GetType() == type))) 
{   DoStuffToArray(instances); }

This is as brief as I can think of ...

You collect the types as a Disctinct list and then iterate to extract. This method uses a lot of reflection, though, so performance will not be optimal.

Dr Herbie
  • 3,930
  • 1
  • 25
  • 28