C# use System.Type as Generic parameter
Asked Answered
F

3

121

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?

Fledgling answered 12/1, 2011 at 10:58 Comment(0)
P
120

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.

Prefab answered 12/1, 2011 at 11:0 Comment(8)
I read about a solution which uses reflection to call the method. But I hoped there was another solution.Fledgling
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<T>) . How can I cast the object to the type I have?Fledgling
@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?Prefab
@Jon: Thanks, I will try writing my own generic method. Unfortunately the non-generic Iqueryable won't solve to problem.Fledgling
@Jon: using my own generic method to call another generic method solved the problemFledgling
What if the function is async?Ultrasonics
@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.Prefab
@Fledgling please post your solutionAssuming
T
44

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});
Tjirebon answered 12/1, 2011 at 11:1 Comment(0)
G
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;
    }
}
Gullet answered 15/1, 2020 at 8:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.