我有一个类型列表(System.Type),需要在数据库上查询。
对于每种类型,我需要调用以下扩展方法(这是LinqToNhibernate的一部分):
Session.Linq<MyType>()
但是我没有MyType,但是我想改用Type。
我所拥有的是:
System.Type typeOne;
但是我不能执行以下操作:
Session.Linq<typeOne>()
如何使用类型作为通用参数?
Answers:
您不能直接这样做。泛型的目的是提供编译时类型安全性,您可以在编译时知道自己感兴趣的类型,并且可以使用该类型的实例。在您的情况下,您仅知道,Type
因此您无法进行任何编译时检查,以确保您拥有的任何对象都是该类型的实例。
您需要通过反射调用该方法-类似于:
// 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);
如果您需要大量使用此类型,则可能会发现编写自己的泛型方法(调用它所需的任何其他泛型方法),然后通过反射调用您的泛型方法更为方便。
IQueryable
会满足您的需求吗?
为此,您需要使用反射:
typeof(Session).GetMethod("Linq").MakeGenericMethod(typeOne).Invoke(null, null);
(假设这Linq<T>()
是该类型的静态方法Session
)
如果Session
实际上是object,则需要知道该Linq
方法的实际声明位置,并将其Session
作为参数传递:
typeof(DeclaringType).GetMethod("Linq").MakeGenericMethod(typeOne)
.Invoke(null, new object[] {Session});
我有一个通用的方法,它称为“通过反射调用泛型方法”
/// <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;
}
}