Вызов обобщенного метода с аргументом типа, известным только во время выполнения

Edit:

Конечно, мой настоящий код выглядит не так. Я попытался написать полу-псевдокод, чтобы сделать его более ясным из того, что я хотел сделать.

Похоже, что это просто испортило ситуацию.

Итак, что я действительно хотел бы сделать, так это:

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

Я получаю "Не могу применить оператор" < ' к операндам типа "группа методов" и "System.Type" " Любая идея о том, как обойти эту проблему?

Ответ 1

EDIT: Хорошо, время для короткой, но полной программы. Основной ответ по-прежнему:

  • Найти "открытый" общий метод с помощью 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
        }
    }
}

Оригинальный ответ

Оставьте в стороне очевидные проблемы вызова переменной "interface" для начала.

Вы должны называть это отражением. Точка дженериков заключается в том, чтобы больше проверять тип во время компиляции. Вы не знаете, что такое тип во время компиляции, поэтому вы должны использовать дженерики.

Получите общий метод и вызовите MakeGenericMethod, затем вызовите его.

Является ли ваш тип интерфейса фактически общим? Я спрашиваю, потому что вы вызываете MakeGenericType на нем, но не передаете какие-либо аргументы типа... Вы пытаетесь вызвать

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

или

Method<MyNamespace.Interface>();

Если это последний, вам нужен только вызов MakeGenericMethod - не MakeGenericType.