116

I have a list of types (System.Type) which need te be queried on the database.

For each of this types, I need to call the following extensionmethod (which is part of LinqToNhibernate):

Session.Linq<MyType>()

However I do not have MyType, but I want to use a Type instead.

What I have is:

System.Type typeOne;

But I cannot perform the following:

Session.Linq<typeOne>()

How can I use a Type as a Generic parameter?

Jan
  • 9,858
  • 7
  • 26
  • 33

3 Answers3

116

You can't, directly. The point of generics is to provide compile-time type safety, where you know the type you're interested in at compile-time, and can work with instances of that type. In your case, you only know the Type so you can't get any compile-time checks that any objects you have are instances of that type.

You'll need to call the method via reflection - something like this:

// Get the generic type definition
MethodInfo method = typeof(Session).GetMethod("Linq", 
                                BindingFlags.Public | BindingFlags.Static);

// Build a method with the specific type argument you're interested in
method = method.MakeGenericMethod(typeOne);
// The "null" is because it's a static method
method.Invoke(null, arguments);

If you need to use this type a lot, you might find it more convenient to write your own generic method which calls whatever other generic methods it needs, and then call your method with reflection.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 2
    I read about a solution which uses reflection to call the method. But I hoped there was another solution. – Jan Jan 12 '11 at 11:04
  • the invoke method returns an "Object". I am not able to query on this object untill I cast it to the correct Type. (Which would probably be IQueryable) . How can I cast the object to the type I have? – Jan Jan 12 '11 at 11:14
  • 3
    @Jan: You can't - but then you wouldn't be able to use that type either, because you don't know the type at compile-time... this is where it may be worth you writing a generic method which does everything you want in a strongly-typed way, and calling *that* with reflection. Alternatively, does the non-generic `IQueryable` do what you need? – Jon Skeet Jan 12 '11 at 11:16
  • 2
    @Jon: Thanks, I will try writing my own generic method. Unfortunately the non-generic Iqueryable won't solve to problem. – Jan Jan 12 '11 at 11:22
  • 1
    @Jon: using my own generic method to call another generic method solved the problem – Jan Jan 12 '11 at 13:39
  • What if the function is async? – Red Riding Hood Mar 24 '19 at 09:14
  • @RedRidingHood: Async is a compile-time detail. You'd invoke the method in the same way, but presumably use the returned task. You'd want to do that for non-async methods returning a task, too. – Jon Skeet Mar 24 '19 at 09:28
  • @Jan please post your solution – Paul Efford Mar 09 '23 at 06:02
41

To do this you need to use reflection:

typeof(Session).GetMethod("Linq").MakeGenericMethod(typeOne).Invoke(null, null);

(assuming that Linq<T>() is a static method on the type Session)

If Session is actually an object, you'll need to know where the Linq method is actually declared, and pass in Session as an argument:

typeof(DeclaringType).GetMethod("Linq").MakeGenericMethod(typeOne)
     .Invoke(null, new object[] {Session});
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
1

I have one general method which call Call Generic Method Through Reflection

/// <summary>
/// This method call your method through Reflection 
/// so i wil call the method like CallGenericMethodThroughReflection<Session>(assemblyQualifiedName,Linq,false,new[] { file }) 
/// </summary>
/// <typeparam name="T">Call method from which file</typeparam>
/// <param name="assemblyQualifiedName">Your can get assemblyQualifiedName like typeof(Payroll.Domain.Attendance.AttendanceApplicationMaster).AssemblyQualifiedName</param>
/// <param name="methodName"></param>
/// <param name="isStaticMethod"></param>
/// <param name="paramaterList"></param>
/// <param name="parameterType">pass parameter type list in case of the given method have overload  </param>
/// <returns>return object of calling method</returns>
public static object CallGenericMethodThroughReflection<T>(string assemblyQualifiedName, string methodName,bool isStaticMethod ,object[] paramaterList,Type[] parameterType = null)
{
    try
    {
        object instance = null;
        var bindingAttr = BindingFlags.Static | BindingFlags.Public;
        if (!isStaticMethod)
        {
            instance = Activator.CreateInstance<T>();
            bindingAttr = BindingFlags.Instance | BindingFlags.Public;
        }
        MethodInfo MI = null;
        var type = Type.GetType(assemblyQualifiedName);
        if(parameterType == null)
            MI = typeof(T).GetMethod(methodName, bindingAttr);
        else
            MI = typeof(T).GetMethod(methodName, bindingAttr,null, parameterType, null);//this will work in most case some case not work
        if (type == null || MI == null) // if the condition is true it means given method or AssemblyQualifiedName entity not found
            return null;
        var genericMethod = MI.MakeGenericMethod(new[] { type });
        return genericMethod.Invoke(instance, paramaterList);
    }
    catch (Exception ex)
    {
        throw ex;
    }
}
i123iu
  • 19
  • 1
  • 4
Kalpesh Dabhi
  • 760
  • 8
  • 18