2016-09-22 3 views
0

У меня есть класс с несколькими универсальными перегруженными методами. Я пытаюсь получить конкретный по типам его параметров. Это относительно легко сделать, когда я придерживаюсь первых двух (с аргументами типа int и string). Но независимо от того, что я делаю, я не могу заставить свою программу замечать третью, предназначенную для общего списка. Я использую неправильный аргумент типа? Если да, то какой правильный путь?C#: GetMethod по типу (общий список)

/* rest of code */ 
    static void Main(string[] args) { 
     MethodInfo method = 
      typeof(c).GetMethod("m", new Type[] { typeof(int) }); 

     Console.WriteLine(method); 

     method = 
      typeof(c).GetMethod("m", new Type[] { typeof(String) }); 

     Console.WriteLine(method); 

     method = 
      typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<>) }); 

     Console.WriteLine(method); 

     Console.ReadKey(); 
    } 
} 

static class c 
{ 
    public static void m<T>(int i) 
    { 
    } 

    public static void m<T>(String s) 
    { 
    } 

    public static void m<T>(IEnumerable<T> Ls) 
    { 
    } 
} 
+0

Возможный дубликат [Как использовать отражение для вызова универсального метода?] (Http://stackoverflow.com/questions/232535/how-do-i-use-reflection-to -call-a-generic-method) – CSharpie

+0

@CSharpie Я думаю, что вопрос в том, как получить общий метод сам, и ответы на вопрос, который вы ссылаетесь, на самом деле не затрагивают этого. – strongbutgood

ответ

1

Короткая версия: typeof(IEnumerable<>) не то же самое, как typeof(IEnumerable<T>) (для некоторого T).

Более длинная версия: нет метода void c.m(IEnumerable<> Ls), только перегрузки, где общий параметр будет иметь определенный характер - существующий во время выполнения - тип, где джиттер необходим для создания метода из-за некоторого кода, ссылающегося на создание экземпляра универсального метода ,

Добавьте вызов в тестовый код в какой-то экземпляр общего метода, а затем выполните для этого экземпляра.

Рассмотрим следующий пример:

using System.Collections.Generic; 
using System.Linq; 
using static System.Console; 

class Methods { 
    public static void M(int x)  { 
     // no-op 
    } 

    public static void M<T>(IEnumerable<T> x)  { 
     // no-op 
    } 
} 

class Program { 
    static void Main(string[] args) { 
     Methods.M(0); 
     Methods.M(new[] { "a", "b" }); 

     ShowAllM(); 
    } 

    public static void ShowAllM() { 
     var tm = typeof(Methods); 
     foreach (var mi in tm.GetMethods().Where(m => m.Name == "M")) 
     { 
      WriteLine(mi.Name); 
      foreach (var p in mi.GetParameters()) 
      { 
       WriteLine($"\t{p.ParameterType.Name}"); 
      } 
     } 
    } 
} 

, который производит выходной сигнал:

 
M 
    Int32 
M 
    IEnumerable`1 

обратите внимание, что только один результат от общей перегрузки. Если к M<char>(…) добавлен звонок, то вывод тот же.

Для отражения существует только один метод, аргумент которого отражает его «открытую общую» природу, но это не совсем то же самое, что и вызываемый открытым открытым типом (например, IEnumerable<>), поскольку открытые типы не являются инстанцируемыми ,

(я состряпал много технических детали здесь. Это instruictive смотреть на разнице в отладчике между typeof(IEnumerable<>) и typeof(IEnumerable<int>).)

+0

Можно ли добавить пример кода? Я не думаю, что понимаю, что вы подразумеваете под _GetMethod для этого экземпляра. – Daedan

1

Третьим метод имеет сигнатуру m<T>(IEnumerable<T>), но ваш пример показан попытаться найти метод с сигнатурой m(IEnumerable<>).

Разница между typeof(IEnumerable<T>) и typeof(IEnumerable<>) - это первый тип, а второй - определение общего типа, и это не одно и то же. Общий тип определяется как из определения общего типа, так и из аргументов общего типа.

Имея это в виду, вы хотели бы использовать:

method = 
     typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<MyType>) }); 

и заменить тип перечислимы, что вы будете проходящее в метод.

С другой стороны, если вы не знаете типа перечислим фронт вы могли бы получить общее определение метода и сделать годный к употреблению универсального метода, когда вам это нужно:

methodDef = 
     typeof(c).GetMethod("m", new Type[] { typeof(IEnumerable<object>) }).GetGenericMethodDefinition(); 
method = methodDef.MakeGenericMethod(new Type[] { typeof(MyType) }); 
+0

И можно ли получить его, не изменяя ничего о методе? В настоящее время я работаю с внешней библиотекой, поэтому изменения на самом деле не являются опцией. Я знаю, что я могу получить соответствующий MethodInfo по GetMethods() и искать его для правильного, но это так _crude_ – Daedan

+0

@Daedan да, метод в порядке, так как мои примеры должны работать, чтобы получить MethodInfo, который вы можете использовать вызывать с предположением, что это то, что вы хотите сделать. Как вы используете MethodInfo после его появления? – strongbutgood

+0

У меня его нет 'method = typeof (c) .GetMethod (" m ", new Type [] {typeof (IEnumerable )});' возвращает null. Чтобы получить MethodInfo, мне нужно изменить свой метод, чтобы specyfically принять IEnumerable как аргумент – Daedan

0

Если удалить общие defenitions от Int и строковых методов:

public static void m(int i) 
    { 
    } 

    public static void m(String s) 
    { 
    } 

    public static void m<T>(IEnumerable<T> Ls) 
    { 
    } 

и использовать следующие строки получить необходимые шаблонный метод:

method = typeof(c).GetMethods().FirstOrDefault(m => m.IsGenericMethod && 
        m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() 
         == typeof(IEnumerable<>)); 

Это сделает трюк

Смежные вопросы