C# 使用 System.Type 作为通用参数

Posted

技术标签:

【中文标题】C# 使用 System.Type 作为通用参数【英文标题】:C# use System.Type as Generic parameter 【发布时间】:2011-06-07 18:25:11 【问题描述】:

我有一个需要在数据库中查询的类型列表(System.Type)。

对于每种类型,我需要调用以下扩展方法(它是 LinqToNhibernate 的一部分):

Session.Linq<MyType>()

但是我没有 MyType,但我想使用 Type。

我拥有的是:

System.Type typeOne;

但我无法执行以下操作:

Session.Linq<typeOne>()

如何将类型用作通用参数?

【问题讨论】:

【参考方案1】:

你不能,直接。泛型的重点是提供编译时 类型安全,您可以在编译时知道您感兴趣的类型,并且可以使用该类型的实例。在您的情况下,您只知道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);

如果您需要经常使用这种类型,您可能会发现编写自己的泛型方法更方便,该方法调用它需要的任何其他泛型方法,然后通过反射调用你的方法。

【讨论】:

我读到了一个使用反射来调用方法的解决方案。但我希望有另一种解决方案。 invoke 方法返回一个“对象”。在将其转换为正确的类型之前,我无法查询此对象。 (这可能是 IQueryable) 。如何将对象转换为我拥有的类型? @Jan:你不能——但是你也不能使用那个类型,因为你在编译时不知道类型......这可能是值得你编写一个通用方法,它以强类型的方式完成你想要的一切,并用反射调用 that。或者,非通用 IQueryable 是否满足您的需求? @Jon:谢谢,我会尝试编写自己的通用方法。不幸的是,非泛型 Iqueryable 无法解决问题。 @Jon: 使用我自己的泛型方法调用另一个泛型方法解决了问题【参考方案2】:

为此,您需要使用反射:

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

(假设Linq&lt;T&gt;()Session类型的静态方法)

如果Session 实际上是一个对象,您需要知道Linq 方法的实际声明位置,并将Session 作为参数传入:

typeof(DeclaringType).GetMethod("Linq").MakeGenericMethod(typeOne)
     .Invoke(null, new object[] Session);

【讨论】:

【参考方案3】:

我有一种通用方法,通过反射调用通用方法

/// <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;
        
    

【讨论】:

以上是关于C# 使用 System.Type 作为通用参数的主要内容,如果未能解决你的问题,请参考以下文章

反射 - 从 System.Type 实例获取通用参数

将枚举值作为参数的通用 C# 方法[重复]

将实例化的 System.Type 作为泛型类的类型参数传递

C#:将枚举类型作为参数传递

C#中的泛型,使用变量的类型作为参数[重复]

TypeScript:相当于 C# 的用于扩展类的通用类型约束?