MaYaN MaYaN - 7 days ago 6
C# Question

How can I get the return type of a Func<T> using reflection?

I have the following type hierarchy:

public abstract class Controller {}
public sealed class PersonController : Controller {}
public sealed class OrderController : Controller {}


I also have a method that resolves the instance of a given type on demand (think of it as a layman's IOC):

private void Resolve<T>(Func<T>[] controllerFactories) where T : Controller
{
Array.ForEach(controllerFactories, x =>
{
// This returns Controller instead of the child class
// I need to know the actual type so that I can do other stuff
// before resolving the instance.
Console.WriteLine(x.Method.ReturnType);
var controllerInstance = x();
});
}


I need to figure out the type of
T
in
Func<T>
but when I try:

void Main()
{
var factories = new Func<Controller>[] {
() => new PersonController(),
() => new OrderController()
};

Resolve(factories);
}


I get
Controller
instead of the
PersonController
and
OrderController
.

Any ideas?

Update:



I thank everyone for providing such detailed answers and examples. They prompted me to rethink the API and here is what I finally came up with which serves what I wanted to accomplish:

public interface IResolver<T>
{
void Register<TKey>(Func<TKey> factory) where TKey : T;
T Resolve(Type type);
void ResolveAll();
}

public sealed class ControllerResolver : IResolver<Controller>
{
private Dictionary<Type, Func<Controller>> _factories = new Dictionary<Type, Func<Controller>>();

public void Register<TKey>(Func<TKey> factory) where TKey : Controller
{
_factories.Add(typeof(TKey), factory);
}

public Controller Resolve(Type type) => _factories[type]();

public void ResolveAll()
{
foreach (var pair in _factories)
{
// Correctly outputs what I want
Console.WriteLine(pair.Value.Method.ReturnType);
}
}
}


And here are some usage examples:

void Main()
{
var resolver = new ControllerResolver();
resolver.Register(() => new PersonController());
resolver.Register(() => new OrderController());

resolver.ResolveAll();
resolver.Resolve(typeof(PersonController));
}

Answer

Each method has a return type stored in the assembly, you specified that your methods' return type is Controller. This is the only thing that is guaranteed as an information (That is what we know without executing the method - Also at compile time)

So we know that the method should return Controller or anything that derive from that. We can never know what is the run-time type until we actually call that method.

As an example, what if the method has a code like:

var factories = new Func<Controller>[] {
    () =>
    {
        if ( DateTime.Now.Second % 2 == 0 )
            return new OrderController();
        else
            return new PersonController();
    }
};

If you need to get the run-time type of the object returned, then you need to:

var controllerInstance = x();
Console.WriteLine(controllerInstance.GetType().Name);