使用仅在执行时已知的类型参数调用泛型方法[重复]

Posted

技术标签:

【中文标题】使用仅在执行时已知的类型参数调用泛型方法[重复]【英文标题】:Calling generic method with a type argument known only at execution time [duplicate] 【发布时间】:2008-11-28 06:28:55 【问题描述】:

编辑:

当然,我的真实代码看起来并不完全像这样。我尝试编写半伪代码以更清楚地说明我想要做什么。

看起来只是把事情搞砸了。

所以,我真正想做的是:

Method<Interface1>();
Method<Interface2>();
Method<Interface3>();
...

嗯……我想也许我可以用反射把它变成一个循环。所以问题是:我该怎么做。我对反射的了解非常。所以代码示例会很棒。

场景如下:

public void Method<T>() where T : class

public void AnotherMethod()

    Assembly assembly = Assembly.GetExecutingAssembly();

    var interfaces = from i in assembly.GetTypes()
    where i.Namespace == "MyNamespace.Interface" // only interfaces stored here
    select i;

    foreach(var i in interfaces)
    
        Method<i>(); // Get compile error here!
    


原帖:

嗨!

我正在尝试遍历命名空间中的所有接口,并将它们作为参数发送到这样的泛型方法:

public void Method<T>() where T : class

public void AnotherMethod()

    Assembly assembly = Assembly.GetExecutingAssembly();

    var interfaces = from i in assembly.GetTypes()
    where i.Namespace == "MyNamespace.Interface" // only interfaces stored here
    select i;

    foreach(var interface in interfaces)
    
        Method<interface>(); // Get compile error here!
    

我得到的错误是“需要类型名称,但找到了局部变量名称”。 如果我尝试

...
    foreach(var interface in interfaces)
    
        Method<interface.MakeGenericType()>(); // Still get compile error here!
    

我得到“无法将运算符'

【问题讨论】:

【参考方案1】:

编辑:好的,是时候进行一个简短但完整的程序了。基本答案如前:

使用 Type.GetMethod 查找“开放”泛型方法 使用 MakeGenericMethod 使其通用 用 Invoke 调用它

这里有一些示例代码。请注意,我将查询表达式更改为点表示法 - 当您基本上只有一个 where 子句时,使用查询表达式是没有意义的。

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
        
    

原答案

让我们先把调用变量“接口”的明显问题放在一边。

你必须通过反射来调用它。泛型的重点是在编译时进行更多类型检查。您在编译时不知道类型是什么 - 因此您必须使用泛型。

获取泛型方法,并在其上调用 MakeGenericMethod,然后调用它。

您的接口类型本身实际上是通用的吗?我问是因为您在其上调用 MakeGenericType,但没有传入任何类型参数...您是否尝试调用

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

Method<MyNamespace.Interface>();

如果是后者,您只需要调用 MakeGenericMethod - 而不是 MakeGenericType。

【讨论】:

我想根据类型对泛型方法进行存根。但是,如果我使用反射制作它,然后存根生成的,它就会明白它不会存根我想要的东西。我的猜测是这是不可能的?或者是吗?存根列表中所有类型的通用方法... @Stephane:很难确切地知道你想要做什么。我建议你问一个更详细的新问题。 请注意,您可能会在GetMethod() 上收到“方法解析中的模糊匹配”。当您尝试获取的方法有一些重载时,就会发生这种情况。所以你需要使用GetMethod("Name", new Type[] arguments) 指定你想要的那个

以上是关于使用仅在执行时已知的类型参数调用泛型方法[重复]的主要内容,如果未能解决你的问题,请参考以下文章

c#使用泛型方法,在运行时已知类型的异步方法

使用 Lambda 表达式调用通用方法(以及仅在运行时知道的类型)

使用类型变量调用泛型方法[重复]

Java泛型

Java泛型

泛型与反射