2010-07-09 3 views
48

Можно создать дубликат:
Will code in a Finally statement fire if I return a value in a Try block?Выполняет ли блок C# «finally» ВСЕГДА?

Рассмотрим следующий код C# код. Выполняется ли блок «finally»?

public void DoesThisExecute() { 
    string ext = "xlsx"; 
    string message = string.Empty; 
    try { 
     switch (ext) { 
     case "xls": message = "Great choice!"; break; 
     case "csv": message = "Better choice!"; break; 
     case "exe": message = "Do not try to break me!"; break; 
     default: 
      message = "You will not win!"; 
      return; 
     } 
    } 
    catch (Exception) { 
     // Handle an exception. 
    } 
    finally { 
     MessageBox.Show(message); 
    } 
} 

Ha, после того, как я закончил писать это, я понял, что мог бы протестировать это сам в Visual Studio. Однако, пожалуйста, не стесняйтесь отвечать!

+4

Нет. Вы получите ошибку компилятора. – Zano

+6

Единственное, что не компилируется, - это пропущенная точка с запятой после объявления «ext». –

+1

@ Zano - Отсутствует; была опечатка :) –

ответ

9
+38

Нет, это не так. http://thedailywtf.com/Articles/My-Tales.aspx –

+5

@IvanZlatanov Ответ правильный в контексте вопроса, в котором OP, по-видимому, хочет знать, будет ли наконец выполняться даже после оператора return, однако вы правильно, что есть обстоятельства, при которых, наконец, не будут выполняться. –

+0

О, ты был бы удивлен. Проверьте это: static int Main (string [] arguments) { try { return arguments [1000] .Length; } finally { System.Console.WriteLine («вы никогда этого не увидите!»); } } –

0

Простой ответ Да. Но есть некоторые «исключения» для правила.

+2

Вы видели инструкцию 'return'? –

+6

@Gary: заявление о возвращении не является оправданием. – EFraim

+2

Он все равно будет вводить оператор finally независимо от оператора return. –

1

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

4

Из MSDN try-finally (C# Reference)

Окончательно блок полезен для очистки любых ресурсов, выделяемых в блок TRY, а также работает под управлением любой код, который должен выполнить, даже если является исключением. Управление всегда передано блоку finally независимо от того, как выйдет блок try.

1

Да, при нормальных обстоятельствах (как указывали многие другие).

Окончательно блок полезен для очистки любых ресурсов, выделенных в Попробовать блока, а также работает под управлением любой код, который должен выполнить, даже если является исключением. Управление всегда передано блоку finally независимо от того, как выйдет блок try.

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

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

41

Из MSDN C# спецификации заявления попробовать.

Операторы блока finally всегда выполняются, когда управление оставляет заявление о попытке. Это верно происходит ли передача управления, как результата нормального выполнения, как результате выполнения перерыва, продолжать, Гота, или возвратить, или как результате распространяющееся исключение из заявления Ьги оператора try.

Источник ссылка:

http://msdn.microsoft.com/en-us/library/aa664733(v=VS.71).aspx

Есть случаи, когда, наконец, блок не исполнит.

  1. Environment.FailFast
  2. в неуловимом execeptions
  3. Функционирует
+0

Я этого не знал! :) –

+0

@Gary Willoughby, я знал, что это так, но я не хотел ошибаться, поэтому я просто искал эту спецификацию. – msarchet

+0

Спецификация неверна. Попробуйте это: static int Main (string [] arguments) { try { return arguments [1000] .Length; } finally { System.Console.WriteLine («вы никогда этого не увидите!»); } } –

68

Нет это не так. Он всегда будет выполняться, если приложение все еще работает (за исключением исключения FastFail, MSDN link, как и другие). Он будет выполняться, когда он выйдет из блока try/catch блока.

Он не будет выполнен, если приложение аварийно завершает работу: происходит уничтожение с помощью команды процесса уничтожения и т. Д. Это очень важно, потому что, если вы пишете код, который абсолютно ожидает его запуска, например, вручную выполняет откат, а если не другой если он будет автоматически зафиксирован, вы можете запустить сценарий, который приложение прерывает до того, как это произойдет. Честно говоря, это внешний сценарий, но важно учитывать в этих ситуациях.

+4

Это также включает в себя некоторые Исключения (три исключения .net, которые невозможно поймать), Application.FailFast или Power Outage (http://thedailywtf.com/Articles/My-Tales.aspx) –

+0

И это не будет выполнить, если код не компилируется и не запускается, как этого, вероятно, не будет, из-за оператора return. – DOK

+4

@DOK Что случилось с заявлением о возврате? –

1

Правильный ответ: Да.

Попробуйте отладить свою программу и поместите точку останова и посмотрите, как управление все еще попадает в блок finally.

1

Нет, это не так.

Существует только один путь вокруг него, и это Environment.FailFast(). См. http://msdn.microsoft.com/de-de/library/ms131100.aspx. В любом другом случае гарантируется, что финализаторы получить казнены ;-)

Метод FailFast записывает строку сообщение в журнале событий приложений Windows, создает дамп вашего приложения, а затем завершает ток обработать. Строка сообщения также включена в отчет об ошибках в Microsoft.

Используйте метод FailFast вместо метода Выхода для завершения вашего приложения, если состояние вашего приложения повреждено и не подлежит ремонт, и выполнение Try /, наконец, блоков вашего приложения и финализаторы воля коррумпированных программы ресурсов.

+1

Все, что прекращает процесс, а не позволяет ему закрыть себя мягко, будет препятствовать запуску. –

29

Не совсем верно, что finally всегда будет выполняться.См this answer от Haacked:

две возможности:

  • StackOverflowException
  • ExecutingEngineException

Окончательно блок не будут выполнены , когда есть StackOverflowException так как нет места на стек до даже exec ute больше кода. Он будет также не будет называться, когда есть ExecutingEngineException, которое очень редко.

В самом деле, для любого вида асинхронного исключения (как StackOverflowException, OutOfMemoryException, ThreadAbortException) выполнение в finally блока не гарантируется.

Однако эти исключения являются исключениями, от которых обычно не удается восстановить, и в большинстве случаев ваш процесс все равно выйдет.

В самом деле, есть и по крайней мере один другой случай, когда finally не выполняется, как описано Brian Rasmussen в настоящее deleted question:

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

Приведенный ниже код иллюстрирует проблему

static void Main(string[] args) { 
    try { 
     DisposableType d = new DisposableType(); 
     d.Dispose(); 
     d = null; 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
    } catch { 
     Console.WriteLine("catch"); 
    } finally { 
     Console.WriteLine("finally"); 
    } 
} 

public class DisposableType : IDisposable { 
    public void Dispose() { 
    } 

    ~DisposableType() { 
     throw new NotImplementedException(); 
    } 
} 

Надежный TRY/поймать/наконец, придется использовать Constrained Execution Regions (CER). example обеспечивается MSDN:

[StructLayout(LayoutKind.Sequential)] 
struct MyStruct 
{ 
    public IntPtr m_outputHandle; 
} 

sealed class MySafeHandle : SafeHandle 
{ 
    // Called by P/Invoke when returning SafeHandles 
    public MySafeHandle() 
     : base(IntPtr.Zero, true) 
    { 
    } 

    public MySafeHandle AllocateHandle() 
    { 
     // Allocate SafeHandle first to avoid failure later. 
     MySafeHandle sh = new MySafeHandle(); 

     RuntimeHelpers.PrepareConstrainedRegions(); 
     try { } 
     finally 
     { 
      MyStruct myStruct = new MyStruct(); 
      NativeAllocateHandle(ref myStruct); 
      sh.SetHandle(myStruct.m_outputHandle); 
     } 

     return sh; 
    } 
} 

отличным источником информации является следующая статья:

Reliability Best Practices

+0

Не могли бы вы поддержать то, что вы сказали о 'ThreadAbortException', не запускающем' finally'? –

+0

Согласен, я уверен, что ThreadAbortException пытается выполнить блок finally. Он одобряет окончательный блок, фактически отменяющий поток, поэтому последний менее гарантирован, чем первый. – David

+0

@Steven Sudit, @David: Извините, я, вероятно, не был прав по этому поводу. У меня как-то было это в затылке, но MSDN четко заявляет, что 'finally' будет выполнен. –

2

Окончательно блок будет работать, прямо между этими линиями:

message = "You will not win!"; 
return;