Calling Generic Method with a Type Argument Known Only at Execution Time

Calling generic method with a type argument known only at execution time

EDIT: Okay, time for a short but complete program. The basic answer is as before:

  • Find the "open" generic method with Type.GetMethod
  • Make it generic using MakeGenericMethod
  • Invoke it with Invoke

Here's some sample code. Note that I changed the query expression to dot notation - there's no point in using a query expression when you've basically just got a where clause.

using System;
using System.Linq;
using System.Reflection;

namespace Interfaces
{
interface IFoo {}
interface IBar {}
interface IBaz {}
}

public class Test
{
public static void CallMe<T>()
{
Console.WriteLine("typeof(T): {0}", typeof(T));
}

static void Main()
{
MethodInfo method = typeof(Test).GetMethod("CallMe");

var types = typeof(Test).Assembly.GetTypes()
.Where(t => t.Namespace == "Interfaces");

foreach (Type type in types)
{
MethodInfo genericMethod = method.MakeGenericMethod(type);
genericMethod.Invoke(null, null); // No target, no arguments
}
}
}

Original answer

Let's leave aside the obvious problems of calling a variable "interface" to start with.

You have to call it by reflection. The point of generics is to put more type checking at compile time. You don't know what the type is at compile-time - therefore you've got to use generics.

Get the generic method, and call MakeGenericMethod on it, then invoke it.

Is your interface type itself actually generic? I ask because you're calling MakeGenericType on it, but not passing in any type arguments... Are you trying to call

Method<MyNamespace.Interface<string>>(); // (Or whatever instead of string)

or

Method<MyNamespace.Interface>();

If it's the latter, you only need a call to MakeGenericMethod - not MakeGenericType.

How do you call a generic method if you only know the type parameter at runtime?

You need to call it using reflection:

var method = typeof(SomeClass).GetMethod("SomeMethod");
method.MakeGenericMethod(someType).Invoke(...);

How do I use reflection to call a generic method?

You need to use reflection to get the method to start with, then "construct" it by supplying type arguments with MakeGenericMethod:

MethodInfo method = typeof(Sample).GetMethod(nameof(Sample.GenericMethod));
MethodInfo generic = method.MakeGenericMethod(myType);
generic.Invoke(this, null);

For a static method, pass null as the first argument to Invoke. That's nothing to do with generic methods - it's just normal reflection.

As noted, a lot of this is simpler as of C# 4 using dynamic - if you can use type inference, of course. It doesn't help in cases where type inference isn't available, such as the exact example in the question.

Delegate with generic type only known at runtime

I'd advise having generic and non-generic versions of the method, much like List<T> implements IEnumerable<T> while also explicitly implementing System.Collections.IEnumerable.

"Type known only at runtime" is exactly what generics aren't intended to be used for. The way you're calling this method, you only ever get object out of it anyway. Better to have a real ordinary non-generic method that just returns object.

   T GetOfType<T>();
object GetOfType(Type t);

You don't even need to worry about overload resolution. There's some extra burden placed on the class implementing the interface, admittedly. But as you've seen, there's going to be a burden somewhere.

Call generic method which T is a Type

You want to use the MakeGenericMethod method that is available on MethodInfo, e.g

    someTarget.GetType()
.GetMethod("SomeGenericMethod")
.MakeGenericMethod(typeof(SomeGenericArgument)
.Invoke(someTarget, someParameters);

See also:

Calling generic method with a type argument known only at execution time

EDIT - For given example

orderBiz.GetOrderDynamically<tt>(selectExp, predicateExp); – unos
baghaii 5 mins ago

    orderBiz.GetType().GetMethod("GetOrderDynamically").MakeGenericMethod(tt).Invoke(orderBiz, new object [] { selectExp, predicateExp });

Function returning a generic type whose value is known only at runtime

typeof(IContainer<>).MakeGenericType(type) will only evaluate at runtime, while "as" needs to know the type at compiler time.

What I really don't understand is this comment: My problem is that I don't know how to enumerate the result which has type Object (therefore I cannot cast it to IEnumerable).

myContainer may be an Object but it can surely be cast to IEnumerable? If it can't then it can't be enumerated.

How to do a generic call to function based on a Type object?

You need to use reflection:

public IEnumerable GetBoxed(Type type, string param1, string param2)
{
return (IEnumerable)this
.GetType()
.GetMethod("Get")
.MakeGenericMethod(type)
.Invoke(this, new[] { param1, param2 });
}

Java determines which method to call using a generic type argument?

What happens here is that the compiler can distinguish the two constructors by using generics, so it does before creating the byte code and before stripping generics.

In the middle case, it will tell the VM to invoke MyClass2<init>(Collection) (i.e. generate byte code which matches this specific constructor).

The VM doesn't try to determine which method matches at runtime. That would be way too slow. Instead, it relies on the compiler creating very specific instructions.

This is why the code above works even though the generic information has been erased at runtime.

[EDIT] To clarify: The byte code contains additional information which the compiler can see and use. You can get the same information via reflection.

Erasure means that the byte code interpreter and JIT doesn't care about generics which is why you can't have setFoo(List<String>) and setFoo(List<Integer>) in the same class: While the compiler could distinguish the two, the runtime can't.

Specifically, when you examine a method via reflection, you will get generics information but the byte code interpreter / JIT doesn't use reflection. Instead, it uses the compressed method signature which reads something like Method com/pany/Type/setFoo(Ljava.util.List;)V - no generics here anymore.

Related:

  • How the Java virtual machine handles method invocation and return
  • Why do the Java bytecodes for invoking methods implicitly acquire and release monitors?
  • invokevirtual docs

Generic Method Executed with a runtime type

You can, but it involves reflection, but you can do it.

typeof(ClassExample)
.GetMethod("DoSomething")
.MakeGenericMethod(p.DisplayType)
.Invoke(this, new object[] { p.Name, p.Value });

This will look at the top of the containing class, get the method info, create a generic method with the appropriate type, then you can call Invoke on it.



Related Topics



Leave a reply



Submit