引用所需的重载泛型方法

发布于 2024-07-14 00:47:46 字数 525 浏览 6 评论 0原文

给定的

public Class Example
{

public static void Foo< T>(int ID){}

public static void Foo< T,U>(int ID){}

}

问题:

  1. 将其称为“重载通用方法”是否正确?
  2. 如何在创建 MethodInfo 对象时指定任一方法?

    类型 exampleType = Type.GetType("完全限定的nameOfExample,namespaceOfExample"); 
      MethodInfo mi = exampleType.GetMethod("Foo", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof(Type), typeof(Type) }, null); 
      

参数 4 导致编译器非常不满

given

public Class Example
{

public static void Foo< T>(int ID){}

public static void Foo< T,U>(int ID){}

}

Questions:

  1. Is it correct to call this an "overloaded generic method"?
  2. How can either method be specified in creation of a MethodInfo object?

    Type exampleType = Type.GetType("fullyqualifiednameOfExample, namespaceOfExample");
    MethodInfo mi = exampleType.GetMethod("Foo", BindingFlags.Public|BindingFlags.Static, null, new Type[] {typeof(Type), typeof(Type) }, null);
    

argument 4 causes the compiler much displeasure

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

暮色兮凉城 2024-07-21 00:47:46

我找不到一种使用 GetMethod 来完成您想要的操作的方法。 但您可以获取所有方法并浏览列表,直到找到所需的方法。

请记住,您需要先调用 MakeGenericMethod,然后才能实际使用它。

var allMethods = typeof (Example).GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo foundMi = allMethods.FirstOrDefault(
    mi => mi.Name == "Foo" && mi.GetGenericArguments().Count() == 2);
if (foundMi != null)
{
    MethodInfo closedMi = foundMi.MakeGenericMethod(new Type[] {typeof (int), typeof (string)});
    Example example= new Example();
    closedMi.Invoke(example, new object[] { 5 });
}

I can't find a way of using GetMethod that would do what you want. But you can get all the methods and go through the list until you find the method that you want.

Remember you need to call MakeGenericMethod before you can actually use it.

var allMethods = typeof (Example).GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo foundMi = allMethods.FirstOrDefault(
    mi => mi.Name == "Foo" && mi.GetGenericArguments().Count() == 2);
if (foundMi != null)
{
    MethodInfo closedMi = foundMi.MakeGenericMethod(new Type[] {typeof (int), typeof (string)});
    Example example= new Example();
    closedMi.Invoke(example, new object[] { 5 });
}
挽手叙旧 2024-07-21 00:47:46

以下是您的问题的答案以及示例:

  1. 是的,尽管这里对于泛型方法有两件事确实需要注意:类型推断和重载方法解析。 类型推断发生在编译时,编译器尝试解析重载方法签名之前。 编译器将类型推断逻辑应用于共享相同名称的所有泛型方法。 在重载解析步骤中,编译器仅包含那些类型推断成功的泛型方法。 更多信息...

  2. 请参阅下面的完整示例控制台应用程序代码显示了如何在创建 MethodInfo 对象时指定 Foo 方法的多个变体,然后使用扩展方法调用:

Program.cs

class Program
{
    static void Main(string[] args)
    {
        MethodInfo foo1 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string) },
            new[] { typeof(int) },
            typeof(void));

        MethodInfo foo2 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string), typeof(int) },
            new[] { typeof(int) },
            typeof(void));

        MethodInfo foo3 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string) },
            new[] { typeof(string) },
            typeof(void));

        MethodInfo foo4 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string), typeof(int) },
            new[] { typeof(int), typeof(string) },
            typeof(string));

        Console.WriteLine(foo1.Invoke(null, new object[] { 1 }));
        Console.WriteLine(foo2.Invoke(null, new object[] { 1 }));
        Console.WriteLine(foo3.Invoke(null, new object[] { "s" }));
        Console.WriteLine(foo4.Invoke(null, new object[] { 1, "s" }));
    }
}

Example.cs:

public class Example
{
    public static void Foo<T>(int ID) { }
    public static void Foo<T, U>(int ID) { }
    public static void Foo<T>(string ID) { }
    public static string Foo<T, U>(int intID, string ID) { return ID; }
}

Extensions.cs:

public static class Extensions
{
    public static MethodInfo GetGenericMethod(this Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
    {
        MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
                           where m.Name == name &&
                           m.GetGenericArguments().Length == genericArgTypes.Length &&
                           m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(argTypes) &&
                           m.ReturnType == returnType
                           select m).Single().MakeGenericMethod(genericArgTypes);

        return foo1;
    }
}

Here are the answers to your questions along with an example:

  1. Yes, although there are two things really to be aware of here with generic methods, type inference and overload method resolution. Type inference occurs at compile time before the compiler tries to resolve overloaded method signatures. The compiler applies type inference logic to all generic methods that share the same name. In the overload resolution step, the compiler includes only those generic methods on which type inference succeeded. More here...

  2. Please see the full example Console Application program code below that shows how several variants of the Foo method can be specified in creation of a MethodInfo object and then invoked using an Extension method:

Program.cs

class Program
{
    static void Main(string[] args)
    {
        MethodInfo foo1 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string) },
            new[] { typeof(int) },
            typeof(void));

        MethodInfo foo2 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string), typeof(int) },
            new[] { typeof(int) },
            typeof(void));

        MethodInfo foo3 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string) },
            new[] { typeof(string) },
            typeof(void));

        MethodInfo foo4 = typeof(Example).GetGenericMethod("Foo",
            new[] { typeof(string), typeof(int) },
            new[] { typeof(int), typeof(string) },
            typeof(string));

        Console.WriteLine(foo1.Invoke(null, new object[] { 1 }));
        Console.WriteLine(foo2.Invoke(null, new object[] { 1 }));
        Console.WriteLine(foo3.Invoke(null, new object[] { "s" }));
        Console.WriteLine(foo4.Invoke(null, new object[] { 1, "s" }));
    }
}

Example.cs:

public class Example
{
    public static void Foo<T>(int ID) { }
    public static void Foo<T, U>(int ID) { }
    public static void Foo<T>(string ID) { }
    public static string Foo<T, U>(int intID, string ID) { return ID; }
}

Extensions.cs:

public static class Extensions
{
    public static MethodInfo GetGenericMethod(this Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
    {
        MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
                           where m.Name == name &&
                           m.GetGenericArguments().Length == genericArgTypes.Length &&
                           m.GetParameters().Select(pi => pi.ParameterType).SequenceEqual(argTypes) &&
                           m.ReturnType == returnType
                           select m).Single().MakeGenericMethod(genericArgTypes);

        return foo1;
    }
}
梦幻之岛 2024-07-21 00:47:46

更好:

尝试获得 System.Linq.Enumerable.Select 的正确重载的示例

    private static MethodInfo GetMethod<T>(Expression<Func<T>> expression)
    {
        return ((MethodCallExpression)expression.Body).Method;
    }

    public static void CallSelect()
    {
        MethodInfo definition = GetMethod(() => Enumerable.Select(null, (Func<object, object>)null)).GetGenericMethodDefinition();
        definition.MakeGenericMethod(typeof(int), typeof(int)).Invoke(null, new object[] { new List<int>(), ((Func<int, int>)(x => x)) });
    }

Better:

Example attempt to get the correct overload of System.Linq.Enumerable.Select

    private static MethodInfo GetMethod<T>(Expression<Func<T>> expression)
    {
        return ((MethodCallExpression)expression.Body).Method;
    }

    public static void CallSelect()
    {
        MethodInfo definition = GetMethod(() => Enumerable.Select(null, (Func<object, object>)null)).GetGenericMethodDefinition();
        definition.MakeGenericMethod(typeof(int), typeof(int)).Invoke(null, new object[] { new List<int>(), ((Func<int, int>)(x => x)) });
    }
╭ゆ眷念 2024-07-21 00:47:46

另一种查找所需 MethodInfo 的方法是创建一个委托;

var methodInfo = new Action<int>(Example.Foo<object,object>).Method.GetGenericMethodDefinition();

Another one liner to find the MethodInfo you want is to create a delegate;

var methodInfo = new Action<int>(Example.Foo<object,object>).Method.GetGenericMethodDefinition();
绮烟 2024-07-21 00:47:46

这是满足您需要的 Linq 一行:

MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2);

Here is a Linq one-liner for what you need:

MethodInfo mi = exampleType.GetMethods().First(m=>m.GetGenericArguments().Length == 2);
第七度阳光i 2024-07-21 00:47:46

我对您的 lambda 查询做了一些修改。

当参数类型为通用时,您必须这样做:

我添加 pi.ParameterType.GetGenericTypeDefinition()

,这样

(m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)

该方法工作得非常好

MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
                         where m.Name == name
                         && m.GetGenericArguments().Length == genericArgTypes.Length
                         && m.GetParameters().Select(pi => pi.ParameterType.IsGenericType ? pi.ParameterType.GetGenericTypeDefinition() : pi.ParameterType).SequenceEqual(argTypes) &&
                         (returnType==null || (m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
                         select m).FirstOrDefault();
      if (foo1 != null)
      {
        return foo1.MakeGenericMethod(genericArgTypes);
      }
      return null;

示例:

通过修改我可以调用的方法
这个扩展方法

public static IQueryable<T> FilterCulture<T>(this Table<T> t, IDatabaseFilter filter)

用我的新助手这样

var QueryableExpression = MethodInfoHelper.GetGenericMethod(typeof(LinqFilterExtension), "FilterCulture", new Type[] { rowType }, new Type[] { typeof(Table<>), typeof(IDatabaseFilter) }, typeof(IQueryable<>)); 

我的助手的签名是

   public static MethodInfo GetGenericMethod(Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)

I make a little modification of your lambda query.

When the parameter type si generic you must make that like that :

I add pi.ParameterType.GetGenericTypeDefinition()

and

(m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)

In this way the method working very fine

MethodInfo foo1 = (from m in t.GetMethods(BindingFlags.Public | BindingFlags.Static)
                         where m.Name == name
                         && m.GetGenericArguments().Length == genericArgTypes.Length
                         && m.GetParameters().Select(pi => pi.ParameterType.IsGenericType ? pi.ParameterType.GetGenericTypeDefinition() : pi.ParameterType).SequenceEqual(argTypes) &&
                         (returnType==null || (m.ReturnType.IsGenericType ? m.ReturnType.GetGenericTypeDefinition() : m.ReturnType) == returnType)
                         select m).FirstOrDefault();
      if (foo1 != null)
      {
        return foo1.MakeGenericMethod(genericArgTypes);
      }
      return null;

Example :

With the modification of the method i can call
this extension method

public static IQueryable<T> FilterCulture<T>(this Table<T> t, IDatabaseFilter filter)

With my new Helper like this

var QueryableExpression = MethodInfoHelper.GetGenericMethod(typeof(LinqFilterExtension), "FilterCulture", new Type[] { rowType }, new Type[] { typeof(Table<>), typeof(IDatabaseFilter) }, typeof(IQueryable<>)); 

The signature of my helper is

   public static MethodInfo GetGenericMethod(Type t, string name, Type[] genericArgTypes, Type[] argTypes, Type returnType)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文