Вызов универсального метода с аргументом типа, известным только во время выполнения
Редактировать:
Конечно, мой реальный код выглядит не совсем так. Я попытался написать полупсевдокод, чтобы сделать его более понятным для того, что я хотел сделать.
Похоже, что вместо этого все испортилось.
Итак, что я на самом деле хотел бы сделать это:
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 ответ
РЕДАКТИРОВАТЬ: Хорошо, время для короткой, но полной программы. Основной ответ, как и прежде:
- Найдите "открытый" универсальный метод с Type.GetMethod
- Сделайте это универсальным, используя MakeGenericMethod
- Вызвать его с помощью вызова
Вот пример кода. Обратите внимание, что я изменил выражение запроса на точечную нотацию - нет смысла использовать выражение запроса, когда вы в основном получили предложение 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.