Как вернуть функцию делегата или выражение лямбда в С#?

Я пытаюсь написать метод, чтобы вернуть экземпляр самого себя. Псевдокод

Func<T,Func<T>> MyFunc<T>(T input)
{
    //do some work with input
    return MyFunc;
}

кажется достаточно простым. Но у меня проблема с заданием типа возврата. Тип возврата должен быть делегатом

 which takes T as parameter, then returns a function 
 which takes T as parameter, then returns a function 
 which takes T as parameter, then returns a function

   ...recursive definition

Я уверен, что была какая-то тонкая вещь, которую я не заметил. Может кто-нибудь указать мне на это? Спасибо.

Ответы

Ответ 1

Вы можете сделать это следующим образом:

delegate F<T> F<T>(T obj);

F<T> MyFunc<T>(T obj)
{
    return MyFunc;
}

Но это почти бесполезно. Единственное, что вы действительно можете сделать, это что-то вроде этого, что странно:

void Main()
{
    MyFunc(1)(2)(3)(4);
}

delegate F<T> F<T>(T obj);

F<T> MyFunc<T>(T obj)
{
    Console.WriteLine(obj);
    return MyFunc;
}

Ответ 2

Другой способ сделать это - создать комбинатор. Легкий peasy, но вы не можете сделать это с помощью дженериков из-за этого бесконечного регресса. Вы должны объявить это напрямую:

delegate D D(D d);

То есть D является делегатом, который принимает D и возвращает D.

static D MyCombinator(D d)
{
    return MyCombinator;
}

Еще несколько мыслей о комбинаторах в С# здесь:

http://blogs.msdn.com/b/ericlippert/archive/2006/06/23/standard-generic-delegate-types-part-two.aspx

Ответ 3

Это очень похоже на итератор. Если вы можете реорганизовать код таким образом:

IEnumerator<P> GetEnumerator<T,P>(T input)
{
  while(<some condition>)
  {
     // do some work with input
     yield return results; 
  }
}

Где T - ваш тип ввода, а P - ваш тип результата. Не идентично, но он должен выполнить работу.

Изменить: если вам нужен свободный интерфейс, шаблон в значительной степени задан в камне: вы создаете нестатический класс и возвращаете его из любой функции (которая не является статичной), которую вы вызываете. Нестатическая версия статического класса называется одноэлементным, и вы можете использовать его для этого шаблона.

Ответ 4

Я не уверен, чего вы пытаетесь достичь, но как интуитивное упражнение "могу ли я вернуть метод, который возвращается сам?" следующие работы:

object MyFunc<T>(T input)
{
    Func<T, object> returnValue = MyFunc;
    return returnValue;
}

Как вы говорите, вы не можете вернуть метод Func, поскольку это означает, что тип возвращаемого значения этого делегата должен быть Func, который возвращает Func, который возвращает Func и т.д....

Единственный выход из этой бесконечной рекурсии, которую я вижу, - это вернуть вместо нее object, что требует, чтобы вызывающий персонаж был нажат на правильный тип.

Изменить: Ответ Porges лучше...