Resposta ao Desafio da Semana #4 [Crash - Tratamento de Exceções em C#/VB.NET]


 

Por: Roberto Alexis Farah

Oi pessoal!

Eis a resposta do Desafio da Semana #4.

https://blogs.technet.com/latam/archive/2006/05/12/428158.aspx

PROBLEMA

O comportamento da aplicação pode parecer estranho mas ele é coerente!

Note que o bloco finally deve sempre ser executado. E, de fato, é usado principalmente para liberar recursos reservados no bloco try, independente de uma exceção ter sido lançada ou não.

Portanto, sabemos que o bloco finally deve ser sempre executado e está sendo. (há documentação no MSDN sobre isso)

Pois bem, porque o valor da variável não mudou isso não significa que há um problema no compilador C#.

Afinal, a lógica da aplicação é para retornar o valor da variável “a” dentro do bloco try sem a interferência da execução do bloco finally.

Se uma exceção fosse disparada antes do return seria mais claro ver a necessidade do finally ser executado.

Mas, você poderia perguntar: e se o valor retornado fosse o valor do bloco finally?

Se isso ocorresse seria incoerente pois seria o mesmo que usar esse bloco de código:

public static string makeStrangeStuff()

{

      StrangeStuff.a = "Anomaly";

      try

      {

      }

      finally

  {

            StrangeStuff.a = "Greater Anomaly";

      }

      return StrangeStuff.a;

}

Note que no bloco de código acima temos uma lógica diferente. No código acima o return StrangeStuff.a vem depois do bloco finally, logo, é esperado que o retorno seja o conteúdo do bloco finally!

De volta ao código original, se analisarmos o metadata temos:

        public static string makeStrangeStuff()

        {

                string CS$1$0000;

                StrangeStuff.a = "Anomaly";

                try

                {

                                CS$1$0000 = StrangeStuff.a;

                }

                finally

                {

                                StrangeStuff.a = "Greater Anomaly";

                }

                return CS$1$0000;

        }

Uma variável interna é criada para produzir o resultado atual, entretanto, se você mudar o código de modo a por o return StrangeStuff.a após o finally e usar ILDasm para ver o resultado você vai notar que o código gerado não mudou:

public static string makeStrangeStuff()

{

      StrangeStuff.a = "Anomaly";

      try

      {

      }

      finally

      {

            StrangeStuff.a = "Greater Anomaly";

      }

      return StrangeStuff.a;

}

Nesse caso não há necessidade do compilador criar uma variável interna, a execução é direta.

Em relação ao código original é recomendado se usar saída de métodos (o return no caso) fora do bloco try pois, como vocês viram, pontos de saída dentro do bloco try deixam o código mais difícil de entender, menos legível.

Outro exemplo para ilustrar:

                        static private DateTime Test()

                        {

                                    try

                                    {

                                                return DateTime.Now; // ß Valor retornado não vai mudar após o finally.

                                    }

                                    finally

                                    {

                                                Thread.Sleep(80000);

                                    }

                        }

Infelizmente essa semana não tive tempo de preparar o próximo desafio. L

Mas até semana que vem vou fazê-lo e publicá-lo.

Até lá.