Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling a generic method in a loop with different types known at compile time

Tags:

c#

generics

Let's consider a method in an interface :

public Interface IA {
    T[] Get<T>() where T : IB;
}

In another place I would like to call this method n times for n types which are known at compile time. The following code illustrates my intention.

foreach(Type t in new Type[] { typeof(X), typeof(Y), typeof(Z) }) 
{
    InterfaceXYZImplement[] arr = c.Resolve<IA>().Get<t>();
    //...more here
}

Now, the foreach loop obviously makes the type become a run-time value so I would have to use MakeGenericMethod.

Is there a way to write the code in such a way that I can have the code executed for X, Y and Z, but call the method written only once?

Wrapping the code in a method would only move the problem upwards (which is a partial solution but not the ultimate one, heh).

like image 697
tymtam Avatar asked May 03 '12 09:05

tymtam


1 Answers

You could achieve this using some helper method that makes quite a few assumptions and uses the new dynamic keyword in .NET4.

Basically, the solution makes use of the feature of the DLR to correctly infer the type to be used for a generic method, when the parameter that uses the type is a dynamic. For this to work, you will need two helper methods:

IB[] Get(IA a, Type t)
{
    dynamic dummy = Activator.CreateInstance(t);
    return Get(a, dummy);
}

T[] Get<T>(IA a, T dummy) where T : IB
{
    return a.Get<T>();
}

And your code would call the first of those helper methods:

foreach(var t in new Type[] { typeof(X), typeof(Y), typeof(Z) })
{
    IB[] arr = Get(c.Resolve<IA>(), t);
    // do more stuff here
}

As you can see, this approach has several draw backs:

  1. For each type in the loop, a new instance is created via Activator.CreateInstance(t). This line makes the assumption that there exists a public parameterless constructor that can be used and that this constructor doesn't do anything heavy.
  2. If any of the types in the loop doesn't implement IB this code will throw an exception at runtime. There will be no compile error.
  3. The result is always an array of IB instances, not an array of the specific type.
like image 149
Daniel Hilgarth Avatar answered Sep 21 '22 08:09

Daniel Hilgarth