Основная идея позади вложенных циклов умножение .
Подробно останавливающийся на ответе Michael Burr, если внешнее for
циклы делают только управление количеством, то Вашим вложенным for
циклы [более чем 117] количества является просто более сложный способ выполнить итерации по продукту количеств с синглом for
цикл.
Теперь, давайте расширим эту идею Спискам. При итерации более чем трех списков во вложенных циклах это - просто более сложный способ выполнить итерации по продукту списков с единственным циклом. Но как Вы выражаете продукт трех списков?
Первый, нам нужен способ выразить продукт типов. Продукт двух типов X
и Y
может быть выражен как универсальный тип как [1 111]. Это - просто значение, которое состоит из двух значений, одного из типа X
, другого типа Y
. Это похоже на это:
public abstract class P2 {
public abstract A _p1();
public abstract B _p2();
}
Для продукта трех типов, мы просто имеем P3
с очевидным третьим методом. Продукт трех списков, тогда, достигается путем распределения функтора Списка по типу продукта. Таким образом, продукт [1 115], List
, и List
просто List
. Можно тогда выполнить итерации по этому списку с единственным циклом.
библиотека Functional Java имеет List
тип, который поддерживает умножающиеся списки вместе с помощью первоклассных функций и типов продукта (P2, P3, и т.д. которые также включены в библиотеку).
, Например:
for (String x : xs) {
for (String y : ys) {
for (String z : zs) {
doSomething(x, y, z);
}
}
}
эквивалентно:
for (P3 p : xs.map(P.p3()).apply(ys).apply(zs)) {
doSomething(p._1(), p._2(), p._3());
}
Движение далее с Функциональным Java, можно сделать doSomething
первоклассный, следующим образом. Скажем, doSomething
возвраты Строка:
public static final F, String> doSomething =
new F, String>() {
public String f(final P3 p) {
return doSomething(p._1(), p._2(), p._3());
}
};
Тогда можно устранить для цикла в целом и собрать результаты всех приложений [1 122]:
List s = xs.map(P.p3()).apply(ys).apply(zs).map(doSomething);
Проблема в том, что Параметр IEnumerable <>
, который вы передаете в GetMethod
, не является специализированным. На самом деле это IEnumerable
, где T
указывается методом, который вы пытаетесь получить. Но мы не можем получить T
через MethodInfo.GetGenericArguments ()
, поскольку у нас нет ссылки на метод - мы все еще пытаемся его получить.
К сожалению, именно здесь API отражения не справляется. Не существует перегрузки Type.GetMethod ()
, которая позволяет различать перегруженные методы, один из которых является универсальным.
С учетом сказанного, вы застряли в использовании Type.GetMethods ()
и фильтрации результатов с помощью предиката по вашему выбору. Чтобы получить интересующий вас метод, вы можете сделать следующее:
void getMethod()
{
typeof(A).GetMethods().Where(m =>
m.IsGenericMethod &&
m.GetParameters()[0].ParameterType.GetGenericTypeDefinition()
== typeof(IEnumerable<>));
}
NB Я не проверял, требуется ли вызов GetGenericTypeDefinition ()
; вы можете пропустить его. Идея состоит в том, что вы преобразовываете тип A
в A <>
, но среда выполнения может уже предоставить его вам в этой форме.
(Обновлено в ответ на уточнения вопросов):
Невозможно получить дескриптор метода с помощью GetMethod
(например, одна строка), потому что общие данные для определения метода недоступны, пока у нас не будет метода для проверки.
MethodInfo[] methods = typeof(A).GetMethods(BindingFlags.Static | BindingFlags.Public);
MethodInfo genericMethod = methods.Where(m=>m.IsGenericMethod).First(m=>m.ContainsGenericParameters);
genericMethod = genericMethod.GetGenericMethodDefinition();