Зачем использовать try {} finally {} с пустым блоком try?


239

Я заметил, что в System.Threading.TimerBase.Dispose()методе есть try{} finally{}блок, но try{}он пуст.

Есть ли какое-либо значение в использовании try{} finally{}с пустым try?

http://labs.developerfusion.co.uk/SourceViewer/browse.aspx?assembly=SSCLI&namespace=System.Threading&type=TimerBase

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
internal bool Dispose(WaitHandle notifyObject)
{
    bool status = false;
    bool bLockTaken = false;
    RuntimeHelpers.PrepareConstrainedRegions();
    try {
    }
    finally {
        do {
            if (Interlocked.CompareExchange(ref m_lock, 1, 0) == 0) {
                bLockTaken = true;
                try {
                    status = DeleteTimerNative(notifyObject.SafeWaitHandle);
                }
                finally {
                    m_lock = 0;
                }
            }
            Thread.SpinWait(1);
            // yield to processor
        }
        while (!bLockTaken);
        GC.SuppressFinalize(this);
    }

    return status;
}

System.Diagnostics.Process вокруг строки 2144, а также: referenceource.microsoft.com/#System/services/monitoring/…
Патрик Артнер

Ответы:


171

От http://blog.somecreativity.com/2008/04/10/the-empty-try-block-mystery/ :

Эта методология защищает от вызова Thread.Abort, прерывающего обработку. На странице MSDN Thread.Abort говорится, что «неисполненные блоки finally выполняются до прерывания потока». Таким образом, чтобы гарантировать, что ваша обработка заканчивается, даже если ваш поток прерывается посередине кем-то, вызывающим Abort в вашем потоке, вы можете поместить весь ваш код в блок finally (альтернатива - написать код в блоке catch для определите, где вы были до того, как «попытка» была прервана прерыванием, и продолжайте оттуда, если хотите).


6
Почему бы не использовать msdn.microsoft.com/en-us/library/… ?
Роб Фонсека-Энсор

15
Потому что это было недоступно до .NET 2.0
Ганс Пассант

6
@ RobFonseca-Ensor: потому Thread.BeginCriticalRegion()что не предотвращает прерывание потока, а сообщает среде выполнения, что если поток прерывается, то глобальное состояние повреждено, и весь домен приложения может быть убит из-за жалости.
ккм

9
@HansPassant: BeginCriticalSection()действительно не было в .NET 1.x, но нет причин и следствий, которые вы подразумеваете, говоря, потому что . На самом деле, в .NET 1.x даже finallyпрерывание потока могло прервать даже блок. Эти механизмы служат другой цели: выполнение работы finallyпредотвращает прерывание в середине кода, в то время как BeginCriticalSection()только среда выполнения объявляет, что глобальное состояние находится в опасности.
ккм

Если у разработчика есть время (истина) в окончании, завершится ли когда-нибудь прерывание или технически можно будет игнорировать прерывание бесконечно?
Макс Янг

64

Это необходимо для предотвращения Thread.Abortпрерывания процесса. Документация для этого метода говорит, что:

Неисполненные блоки finally выполняются до прерывания потока.

Это связано с тем, что для успешного восстановления после ошибки ваш код должен быть очищен после себя. Поскольку C # не C ++ - деструкторов в стиле, finallyи usingблоки являются единственным надежным способом обеспечения такой очистки выполняется надежно. Помните, что usingблок превращается в это компилятором:

try {
    ...
}
finally {
    if(obj != null)
        ((IDisposable)obj).Dispose();
}

В .NET 1.x был шанс, что finallyблок будет прерван. Это поведение было изменено в .NET 2.0.

Более того, пустые tryблоки никогда не оптимизируются компилятором.


Спасибо за понимание использования блока.
Стефан

@ Антон, я понимаю, что использование это лучшая практика. Но в целях насмешки иногда требуется реализовать класс-обертку, и одноразовый объект становится переменной частного класса. Если мы сделаем эту оболочку одноразовой, не будет ли GC автоматически обрабатывать удаление переменной частного класса?
Озкан

@Ozkan GC не располагает ничего автоматически. Вам нужно будет реализовать финализатор, обычно вызывая Dispose(false);. docs.microsoft.com/en-us/dotnet/standard/garbage-collection/...
Торарин

@Thorarin извините, но вы ошибаетесь, говоря, что GC не удаляет (завершает) автоматически.
Озкан
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.