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á.