1

I'm familiar with constructing and calling generic methods through reflection, but for some reason, constructing a generic delegate through reflection is tying my brain in knots!

Perhaps it's because the delegate in particular is not the most simple. This isn't specifically a MongoDb question, but in my case what I'm trying to do is register a class map as a root class where the type is in a type variable because I've only just found it out (not fed in generically). Ultimately, the method I need to call looks like this:

    BsonClassMap.RegisterClassMap<T>(Action<BsonClassMap<T>> classMapInitializer)

So in cases where the class I'm mapping isn't a root class, I don't need to pass the delegate, so the code is pretty straightforward:

    MethodInfo method = typeof(BsonClassMap).GetMethod("RegisterClassMap");
    MethodInfo genericMethod = method.MakeGenericMethod(entityType);
    genericMethod.Invoke(null, null);

I've checked out questions such as How can I dynamically create an Action<T> at runtime? and I understand what's going on there, but for some reason the nested generic in my case is throwing me off and I can't wrap my head around it.

I am trying to construct and invoke the equivalent of this:

    BsonClassMap.RegisterClassMap<T>(cm =>
    {
        cm.AutoMap();
        cm.SetIsRootClass(true);
    });

Could someone please explain a bit more about generic delegate creation, particularly where the type in the action has a generic type argument of it's own? An example similar to what I'm trying to do would be great!

James D
  • 360
  • 3
  • 13

1 Answers1

1

You should do exactly what the answer in the linked post did.

First, create a generic method that does the thing:

public static void Perform<T>(BsonClassMap<T> cm) {
    cm.AutoMap();
    cm.SetIsRootClass(true);
}

Then, get the method info of Perform:

var performMethodInfo = typeof(YourType).GetMethod("Perform").MakeGenericMethod(entityType);

Create a Type representing BsonClassMap<T> and create a Type representing Action out of it:

var typeOfBsonClassMap = typeof(BsonClassMap<>).MakeGenericType(entityType);
var typeOfAction = typeof(Action<>).MakeGenericType(typeOfBsonClassMap);

Now use Delegate.CreateDelegate:

var del = Delegate.CreateDelegate(typeOfAction, performMethodInfo);

And then you can pass it into the method:

genericMethod.Invoke(null, new object[] { del });
Sweeper
  • 213,210
  • 22
  • 193
  • 313