C# 使用仅在执行时已知的类型参数调用泛型方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/325156/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 23:15:48  来源:igfitidea点击:

Calling generic method with a type argument known only at execution time

c#linqgenericsreflection

提问by Presidenten

Edit:

编辑:

Of course my real code doesn't look exactly like this. I tried to write semi-pseudo code to make it more clear of whay I wanted to do.

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

Looks like it just messed things up instead.

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

So, what I actually would like to do is this:

所以,我真正想做的是:

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

Well ... I thought that maybe I could turn it into a loop using reflection. So the question is: How how do I do it. I have veryshallow knowledge of reflection. So code examples would be great.

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

The scenario looks like this:

场景如下所示:

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!
    }







Original post:

原帖:

Hi!

你好!

I'm trying to loop through all interfaces in a namespace and send them as arguments to a generic method like this:

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

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!
    }
}

The error I get is "Type name expected, but local variable name found". If I try

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

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

I get "Cannot apply operator '<' to operands of type 'method group' and 'System.Type'" Any idea on how to get around this problem?

我收到“无法将运算符‘<’应用于‘方法组’和‘System.Type’类型的操作数”关于如何解决这个问题的任何想法?

采纳答案by Jon Skeet

EDIT: Okay, time for a short but complete program. The basic answer is as before:

编辑:好的,是时候编写一个简短但完整的程序了。基本答案和以前一样:

  • Find the "open" generic method with Type.GetMethod
  • Make it generic using MakeGenericMethod
  • Invoke it with Invoke
  • 使用 Type.GetMethod 查找“打开”泛型方法
  • 使用 MakeGenericMethod 使其通用
  • 用 Invoke 调用它

Here's some sample code. Note that I changed the query expression to dot notation - there's no point in using a query expression when you've basically just got a where clause.

这是一些示例代码。请注意,我将查询表达式更改为点表示法 - 当您基本上只有一个 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
        }
    }
}

Original answer

原答案

Let's leave aside the obvious problems of calling a variable "interface" to start with.

让我们先抛开调用变量“接口”的明显问题。

You have to call it by reflection. The point of generics is to put more type checking at compiletime. You don't know what the type is at compile-time - therefore you've got to use generics.

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

Get the generic method, and call MakeGenericMethod on it, then invoke it.

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

Is your interface type itself actually generic? I ask because you're calling MakeGenericType on it, but not passing in any type arguments... Are you trying to call

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

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

or

或者

Method<MyNamespace.Interface>();

If it's the latter, you only need a call to MakeGenericMethod - not MakeGenericType.

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