Подтвердить что ты не робот

Использование доходности без возвращаемого типа

У меня очень длинная процедура цикла:

public void Process()
{
    bool done = false;
    do {
        //do stuff
    }while (!done);
}

что я хотел бы расколоть на биты, и у меня появилась процедура вызова, показывающая мой прогресс в каком-то пользовательском интерфейсе. Это библиотека классов, поэтому вызывающим может быть что угодно (Консольное приложение, WinForms, WebApp,...).

Было бы проще, если бы я мог:

public void Process()
{
    bool done = false;
    do {
        //do stuff
        yield return;
    }while (!done);
}

Таким образом, вызывающий может продолжать вызов метода до его завершения.

Это больше напоминает работу для BackgroundWorker, но это похоже на неправильное для консольного приложения... Мне не всегда нужно многопоточность. Или это? Я имею в виду, да, я мог бы просто запустить основной поток консоли, чтобы он закончил.

Мой вопрос: могу ли я использовать "поэтапную" функциональность отложенного исполнения "yield return" без фактического возврата чего-либо?

4b9b3361

Ответ 1

Короче говоря, нет.

yield return должен что-то вернуть.

http://msdn.microsoft.com/en-us/library/9k7k7cf0.aspx

Метод Process должен иметь возвращаемый тип IEnumerable, IEnumerable<T>, IEnumerator или IEnumerator<T>. Вы можете вернуть фиктивный objects, если вы действительно хотите использовать yield.

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

Ответ 2

Функция языка, которую вы хотите, называется coroutine (или, точнее, semicoroutine, но не должна быть педантичной.) С# Блоки итераторов являются слабой формой сопрограммы. Я рекомендую не создавать последовательности "dummy" только потому, что вам нужны сопрограммы.

Оператор await в С# 5 также является формой сопрограммы и может более похож на ваше желаемое решение, особенно если ваша операция логически является асинхронной, с высокой задержкой. Существуют стандартные шаблоны для отчетов о выполнении с асинхронными сопрограммами в С# 5; Я бы начал с этого:

http://blogs.msdn.com/b/dotnet/archive/2012/06/06/async-in-4-5-enabling-progress-and-cancellation-in-async-apis.aspx

Ответ 3

Как уже сказал кто-то другой, нет, что не путь, но почему бы вам просто не использовать обратный вызов Func или Action или что-то, чтобы позволить вызываемому взаимодействовать с вашим циклом?

public void Process(Action callback)
{
    bool done = false;
    do {
        //do stuff
        callback();
    }while (!done);
}

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

Ответ 4

Вы говорите, что хотите, чтобы вызывающий абонент ответил на ход метода. Вы можете вернуть информацию о ходе работы:

class ProgressInfo { ... }
...
yield return new ProgressInfo() { ... };

Затем вызывающий абонент будет foreach по результатам и будет действовать на них.

Это гораздо приятнее, чем если вызывающий объект проверяет глобальное изменяемое состояние. Это функциональное решение.

Ответ 5

Нет, это невозможно. Компилятор генерирует итераторы для вас только тогда, когда тип возврата IEnumerable или IEnumerator.

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