2

I would like to dynamically execute a method on a class that uses a generic type, after finding it using reflection (which looks for an interface implementation).

An example of where I am stuck is below. Help is much appreciated.

Setup

public interface IActionRequired<T> where T : class {
    void DoThis(T[] receivedObjects);
}

public class BookDetails {
    public int BookId { get; set; }

    public string BookName { get; set; }
}

public class LibraryBookReturned : IActionRequired<BookDetails>
{
    public void DoThis(BookDetails[] receivedObjects)
    {
        foreach(var book in receivedObjects)
            System.Console.WriteLine(book.BookName);
    }
}

Example Attempt Using Reflection

Below, I am just using the first implementation but in the real world I'll be using a naming convention to locate the correct implementation.

        var assembly = Assembly.GetCallingAssembly();
        var listOfImplementations = 
                GetAllTypesImplementingOpenGenericType(typeof(IActionRequired<>), assembly);
        var implementation = listOfImplementations.FirstOrDefault();
        var implementationUsesInterface = implementation.GetInterfaces() [0];
        var interfaceUsesType = implementationUsesInterface.GetGenericArguments() [0];

I understand that the below will not work (I get an error saying interfaceUsesType is a variable not a type) but it indicates what I would like to do:

        var instance = 
            assembly.CreateInstance(implementation.FullName) as IActionRequired<interfaceUsesType>;
        var results = this.CheckForMessages<interfaceUsesType>();
        instance.DoThis(results);
Sparked
  • 844
  • 10
  • 25
  • Think you might be looking for something like this: [How To: Call a generic method with a runtime type](https://www.rickvandenbosch.net/blog/how-to-call-a-generic-method-with-a-runtime-type/) – rickvdbosch Jun 11 '18 at 10:43

2 Answers2

2

You're going to have to emit a run-time type specific version of the generic method. Have a look at the MethodInfo.MakeGenericMethod for that one.

The MakeGenericMethod method allows you to write code that assigns specific types to the type parameters of a generic method definition, thus creating a MethodInfo object that represents a particular constructed method. If the ContainsGenericParameters property of this MethodInfo object returns true, you can use it to invoke the method or to create a delegate to invoke the method.

In short (pseudo) code:

this.GetType()
    .GetMethod("CheckForMessages")
    .MakeGenericMethod(interfaceUsesType)
    .Invoke(this, null);

You can also read up on it here: How To: Call a generic method with a runtime type

rickvdbosch
  • 14,105
  • 2
  • 40
  • 53
0

@rickvbosch 's answer was (very nearly) what I needed and definitely the right way to go. However, since I was trying to do two things effectively, I've upvoted his answer and added what I did to get things working as the accepted answer to my original problem, using his suggestion.

        var instance = Activator.CreateInstance(implementation);
        var results = this.GetType()
            .GetMethod("CheckForMessages", BindingFlags.NonPublic | BindingFlags.Instance)
            .MakeGenericMethod(interfaceUsesType)
            .Invoke(this, null) as object[];

        if(results.Count() > 0)
            instance.GetType()
            .GetMethod("DoThis")
            .Invoke(instance, new object[] {results});
Sparked
  • 844
  • 10
  • 25