Почему возврат урожая не может появиться в блоке попытки с выгодой?

Лично я хотел бы использовать Maven surefire JUnit runner для этого.

89
задан Daniel Earwicker 26 January 2009 в 10:19
поделиться

4 ответа

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

существует несколько вещей как это, что я уже встретился:

  • Атрибуты, не бывшие способные быть универсально
  • Неспособность для X для получения из X.Y (вложенный класс в X)
  • поля общественности использования блоков Итератора в сгенерированных классах

В каждом из этих случаев, было бы возможно получить немного больше свободы, за счет дополнительной сложности в компиляторе. Команда сделала прагматический выбор, за который я хвалю их - у меня был бы немного более строгий язык с точным компилятором на 99,9% (да, существуют ошибки; я столкнулся один на ПОЭТОМУ просто на днях), чем более выразительный язык, который не мог скомпилировать правильно.

РЕДАКТИРОВАНИЕ: вот псевдодоказательство того, как это, почему это выполнимо.

Полагают что:

  • можно удостовериться, что сама часть возврата урожая не выдает исключение (предварительно вычислите значение, и затем Вы просто устанавливаете поле и возвращаете "true")
  • , Вам разрешают попытку/выгоду, которая не использует возврат урожая в блоке итератора.
  • Все локальные переменные в блоке итератора являются переменными экземпляра в сгенерированном типе, таким образом, можно свободно переместиться, код к новым методам

Теперь преобразуйте:

try
{
    Console.WriteLine("a");
    yield return 10;
    Console.WriteLine("b");
}
catch (Something e)
{
    Console.WriteLine("Catch block");
}
Console.WriteLine("Post");

в (вид псевдокода):

case just_before_try_state:
    try
    {
        Console.WriteLine("a");
    }
    catch (Something e)
    {
        CatchBlock();
        goto case post;
    }
    __current = 10;
    return true;

case just_after_yield_return:
    try
    {
        Console.WriteLine("b");
    }
    catch (Something e)
    {
        CatchBlock();
    }
    goto case post;

case post;
    Console.WriteLine("Post");


void CatchBlock()
{
    Console.WriteLine("Catch block");
}

единственное дублирование находится в установке блоков попытки/выгоды - но это - что-то, что компилятор может, конечно, сделать.

я, возможно, пропустил что-то здесь - если так, сообщите мне!

48
ответ дан Jon Skeet 5 November 2019 в 14:38
поделиться

Весь эти yield операторы в определении итератора преобразовываются в состояние в конечном автомате, который эффективно использует switch оператор для усовершенствования состояний. Если бы это сделало , генерируют код для yield операторы в попытке/выгоде, которую это должно было бы копировать все в try блок для каждый yield оператор в то время как, исключая любой yield оператор для того блока. Это не всегда возможно, особенно если один yield оператор является иждивенцем на более раннем.

5
ответ дан Mark Cidade 5 November 2019 в 14:38
поделиться

Я размышлял бы, что из-за пути стек вызовов добирается, ранили/раскрутили, когда Вы приводите к возврату из перечислителя, для блока попытки/выгоды становится невозможно на самом деле "поймать" исключение. (потому что блок возврата урожая не находится на стеке, даже при том, что он породил итеративный блок)

Для получения ideea того, что я говорю об установке блок итератора и использование foreach тот итератор. Проверьте то, на что Стек вызовов похож в foreach блоке, и затем проверьте, что это в итераторе пробует/наконец блок.

2
ответ дан StingyJack 5 November 2019 в 14:38
поделиться

Я принял ответ НЕУКРОТИМОЙ СТРЕЛЬБЫ ПО ТАРЕЛОЧКАМ, пока кто-то от Microsoft не приезжает для заливки холодной воды на идее. Но я не соглашаюсь с частью дела вкуса - конечно, корректный компилятор более важен, чем полный, но компилятор C# уже очень умен в разбирании в этом преобразовании для нас, насколько это делает. Немного больше полноты в этом случае сделало бы язык легче использовать, преподавать, объяснить, с меньшим количеством пограничных случаев или глюков. Таким образом, я думаю, что это стоило бы дополнительного усилия. Несколько парней в Редмонде царапают головы в течение двух недель, и в результате миллионы кодеров за следующее десятилетие могут ослабиться немного больше.

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

На самом деле один запрос, который я имею об ответе Jon, относится к броску выражения возврата урожая.

, Очевидно, возврат урожая 10 не так плох. Но это было бы плохо:

yield return File.ReadAllText("c:\\missing.txt").Length;

Так не был бы он иметь больше смысла оценивать эту внутреннюю часть предыдущий блок попытки/выгоды:

case just_before_try_state:
    try
    {
        Console.WriteLine("a");
        __current = File.ReadAllText("c:\\missing.txt").Length;
    }
    catch (Something e)
    {
        CatchBlock();
        goto case post;
    }
    return true;

следующая проблема была бы вложена блоки попытки/выгоды и повторно брошенные исключения:

try
{
    Console.WriteLine("x");

    try
    {
        Console.WriteLine("a");
        yield return 10;
        Console.WriteLine("b");
    }
    catch (Something e)
    {
        Console.WriteLine("y");

        if ((DateTime.Now.Second % 2) == 0)
            throw;
    }
}
catch (Something e)
{
    Console.WriteLine("Catch block");
}
Console.WriteLine("Post");

, Но я уверен, что это возможно...

2
ответ дан Daniel Earwicker 5 November 2019 в 14:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: