【问题标题】:How to call generic method with a given Type object? [duplicate]如何使用给定的 Type 对象调用泛型方法? [复制]
【发布时间】:2023-03-14 17:57:01
【问题描述】:

我想用给定的类型对象调用我的泛型方法。

void Foo(Type t)
{
     MyGenericMethod<t>();
}

显然不行。

我怎样才能让它工作?

【问题讨论】:

标签: c# .net generics reflection types


【解决方案1】:

您的代码示例将不起作用,因为泛型方法需要类型标识符,而不是 Type 类的实例。你必须使用反射来做到这一点:

public class Example {

    public void CallingTest()
    {
        MethodInfo method = typeof (Example).GetMethod("Test");
        MethodInfo genericMethod = method.MakeGenericMethod(typeof (string));
        genericMethod.Invoke(this, null);

    }

    public void Test<T>()
    {
        Console.WriteLine(typeof (T).Name);
    }
}

请记住,这非常脆弱,我宁愿建议找到另一种模式来调用您的方法。

另一个 hacky 解决方案(也许有人可以让它更干净一点)是使用一些表情魔法:

public class Example {

    public void CallingTest()
    {
        MethodInfo method = GetMethod<Example>(x => x.Test<object>());
        MethodInfo genericMethod = method.MakeGenericMethod(typeof (string));
        genericMethod.Invoke(this, null);

    }

    public static MethodInfo GetMethod<T>(Expression<Action<T>> expr)
    {
        return ((MethodCallExpression) expr.Body)
            .Method
            .GetGenericMethodDefinition();
    }

    public void Test<T>()
    {
        Console.WriteLine(typeof (T).Name);
    }
}

注意在 lambda 中将“object”类型标识符作为泛型类型参数传递。无法这么快弄清楚如何解决这个问题。无论哪种方式,我认为这是编译时安全的。只是感觉有点不对劲:/

【讨论】:

  • 我的错,我更改了一些名称(在默认的 C# 控制台应用程序中测试,因此该类称为 Program ;))为您修复它,它应该是您想要的类的名称调用方法。
  • 表达式的好主意。我也想不出一种在不指定至少一个通用虚拟参数的情况下引用通用方法的方法..
  • +1 用于使用 lambda 表达式!
  • 感谢您提供“hacky”表达式(这是 IMO 的最佳做法)作为起点。
  • 谢谢。你拯救了我的一天:)
【解决方案2】:

不幸的是,您需要使用反射(出于 Jared 提到的原因)。例如:

MethodInfo method = typeof(Foo).GetMethod("MyGenericMethod");
method = method.MakeGenericMethod(t);
method.Invoke(this, new object[0]);

显然你会想要在现实中进行更多的错误检查:)


旁注:我的本地 MSDN 没有指定 MakeGenericMethod 中的参数是参数数组,所以我预计需要:

method = method.MakeGenericMethod(new Type[] { t });

但它似乎现实中的参数数组,online MSDN docs 同意。奇怪。

【讨论】:

  • 啊!飞碟让我打败了:/
  • 感谢乔恩的回复。但是我已经给出了正确的方法,为什么我需要按名称加载它们?难道没有更安全的方法不涉及方法名称作为字符串?
  • Cody:我在答案中添加了另一个替代方案(试图击败 Skeet),它不涉及字符串。它不像我想要的那样干净,但我认为这个想法很明确。
  • 我想知道为什么在 C# 程序中没有一种重构安全的方法来传递方法名称。我们可以为此责怪海尔斯伯格先生吗? :)
  • 这不是我第一次需要这样的操作员。我在哪里可以投票?
【解决方案3】:

这种方法行不通。原因是 Type 是一个在运行时确定类型的对象。但是,您正在尝试使用它来调用通用方法。泛型方法调用的类型是在编译时建立的。因此,Type 对象永远不能用于泛型方法的类型参数。

【讨论】:

  • 那有什么办法呢?我也非常喜欢这个话题。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多