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.


http://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á.

Comments (0)