Вопрос

После экспериментов с блоком итератора я заметил, что сгенерированный код IL не соответствует ожиданиям. Вместо блока try-finally генерируется блок try-fault, которого я никогда не видел. Я заметил, что компилятор не позволяет мне использовать ключевое слово error в «рукописном» C #.

Есть ли разница между 2?

Код C #:

static IEnumerable<string> ReadAllLines(string fileName)
{
    using (var file = System.IO.File.OpenText(fileName))
    {
        string s;
        while ((s = file.ReadLine()) != null)
        {
            yield return s;
        }
    }
}

Код MSIL:

.method private hidebysig newslot virtual final instance bool MoveNext() cil managed
{
    .override [mscorlib]System.Collections.IEnumerator::MoveNext
    .maxstack 3
    .locals init (
        [0] bool CS$1<*>,
        [1] int32 CS$4$0001,
        [2] string CS<*>$0002,
        [3] bool CS$4$0003)
    L_0000: ldarg.0 

    // try body

    L_008d: leave.s L_0097
    L_008f: ldarg.0 
    L_0090: call instance void ConsoleApplication2.Program/<ReadAllLines>d__0::System.IDisposable.Dispose()
    L_0095: nop 
    L_0096: endfinally 
    L_0097: nop 
    L_0098: ldloc.0 
    L_0099: ret 
    .try L_0000 to L_008f fault handler L_008f to L_0097
}

Интересная строка - это последняя строка IL, в которой указан обработчик ошибок, где в обычном блоке try-finally указан обработчик finally.

Это было полезно?

Решение

Да, блок finally всегда выполняется при выходе из кадра. Блок сбоев выполняется только в том случае, если исключение разматывается за кадром. Блок сбоев в MoveNext сохраняет семантику использования для случая исключения, сгенерированного из блока try итератора ReadAllLines. Для сохранения семантики использования при нормальном выходе из итератора должен использоваться какой-то другой механизм.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top