17

I need to implement the method:

object GetFactory(Type type);

This method needs to return a Func<T> where typeparam 'T' is the 'type'.

So, my problem is that I don't know how to create a Func<?> at runtime using reflection. Activator.CreateInstance doesn't work because there are no constructors on delegates.

Any Ideas?

Craig Wilson
  • 12,174
  • 3
  • 41
  • 45

4 Answers4

30

You use Delegate.CreateDelegate, i.e. from a MethodInfo; below, I've hard-coded, but you would use some logic, or Expression, to get the actual creation method:

using System;
using System.Reflection;
class Foo {}

static class Program
{
    static Func<T> GetFactory<T>()
    {
        return (Func<T>)GetFactory(typeof(T));
    }
    static object GetFactory(Type type)
    {
        Type funcType = typeof(Func<>).MakeGenericType(type);
        MethodInfo method = typeof(Program).GetMethod("CreateFoo",
            BindingFlags.NonPublic | BindingFlags.Static);
        return Delegate.CreateDelegate(funcType, method);
    }
    static Foo CreateFoo() { return new Foo(); }
    static void Main()
    {
        Func<Foo> factory = GetFactory<Foo>();
        Foo foo = factory();
    }
}

For non-static methods, there is an overload of Delegate.CreateDelegate that accepts the target instance.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

I use this with generics in EF Core including making Expression<Func<SomeModelType,bool>> for let's say a Where clause, you can chain MakeGenericType calls with nested generics.

var someType = SomeDbContext.SomeDataModelExample.GetType();
var funcType1 = typeof(Func<>).MakeGenericType(new Type[] { someType });
var result = Activator.CreateInstance(funcType1);
var result2 = Activator.CreateInstance(funcType1, someParams);
Striped
  • 2,544
  • 3
  • 25
  • 31
John Ernest
  • 785
  • 1
  • 8
  • 20
  • I use this with generics in EF Core including making Expression> for let's say a Where clause, you can chain MakeGenericType calls with nested generics. – John Ernest Nov 08 '20 at 03:41
0

I think the usual approach would be to make the "dumb" version be the thing that you spoof at runtme, and then provide a helper extension method to provide the type-safe version on top of it.

Daniel Earwicker
  • 114,894
  • 38
  • 205
  • 284
  • So, this is in the bowels of an IoC container, and I have to return the object as a strongly typed dependency, not necessarily knowing that what was requested was a Func (it could be a Uri or string). – Craig Wilson Mar 18 '09 at 13:51
0

you could create Expression objects instead of a func, and compile() the expression to get a Func delegate.

Joachim Kerschbaumer
  • 9,695
  • 7
  • 49
  • 84